# Generic - abstract class confusion

**URL:** <https://forum.crystal-lang.org/t/generic-abstract-class-confusion/7533>\
**Category:** Help & Support\
**Created:** [December 16, 2024, 4:13pm UTC](https://forum.crystal-lang.org/t/generic-abstract-class-confusion/7533 "2024-12-16T16:13:07Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![dsisnero](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/dsisnero/32/1843_2.png) [@dsisnero](https://forum.crystal-lang.org/u/dsisnero)\
**Post date:** [December 16, 2024, 4:13pm UTC](https://forum.crystal-lang.org/t/generic-abstract-class-confusion/7533/1 "2024-12-16T16:13:07Z")

</div>

I am getting an error

```auto
In src\cml\event.cr:67:18

 67 | def initialize(@events : Array(Event))
                     ^------
Error: instance variable '@events' of ChooseEvent must be Array(Event), not Array(ReceiveEvent(String))

```

with the following code

```auto

# Event class
abstract class Event(T)
  abstract def sync : T

end

class SendEvent(T) < Event(T)
  
  def initialize(@channel : Channel(T), @value : T)
  end

  def sync : T
    @channel.send(@value)
    @value
  end
end

# Receive event
class ReceiveEvent(T) < Event(T)
  
  def initialize(@channel : Channel(T))
  end

  def sync : T
    @channel.receive
  end
end

class ChooseEvent(T) < Event(T)
  def initialize(@events : Array(Event(T)))
  end

  def sync : T
    # Create a buffered channel with capacity 1
    result_channel = Channel(T).new

    # Use a synchronized mechanism to ensure only one result
    done = Channel(Nil).new

    # Create a fiber for each event
    @events.map do |event|
      spawn do
        begin
          result = event.sync

          # Try to send the result, but only if no result has been sent yet
          select
          when result_channel.send(result)
            done.send(nil)
          else
            # If send fails (channel is full), do nothing
            nil
          end
        rescue ex
          # Optionally log the exception
          # puts "Event failed: #{ex.message}"
        end
      end
    end

    # Wait for the first result
    select
    when result = result_channel.receive
      result
    when done.receive
      # Synchronization point
      result_channel.receive
    end
  end
end

```

---

<div class="post-metadata">

**Author:** ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)\
**Post date:** [December 16, 2024, 4:19pm UTC](https://forum.crystal-lang.org/t/generic-abstract-class-confusion/7533/2 "2024-12-16T16:19:06Z")

</div>

The example code doesn’t reproduce the issue from what I can tell, unless it’s missing some stuff? But if I had to guess I’d say this is basically [Inheritance - Crystal](https://crystal-lang.org/reference/1.14/syntax_and_semantics/inheritance.html#covariance-and-contravariance). I.e. it’s expecting an `Array(Event)` which is an array that can hold any `Event` instance. However it’s actually getting `Array(ReceiveEvent(String))` which means it can only hold `ReceiveEvent(String)` instances, hence the error.

---

<div class="post-metadata">

**Author:** ![dsisnero](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/dsisnero/32/1843_2.png) [@dsisnero](https://forum.crystal-lang.org/u/dsisnero)\
**Post date:** [December 16, 2024, 4:33pm UTC](https://forum.crystal-lang.org/t/generic-abstract-class-confusion/7533/3 "2024-12-16T16:33:42Z")

</div>

It does seem to be the problem - How can I correctly initialize the ChooseEvent? I am going to have many types of Event classes - WrapEvent GuardEvent, NackEvent etc -

---

<div class="post-metadata">

**Author:** ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)\
**Post date:** [December 16, 2024, 4:36pm UTC](https://forum.crystal-lang.org/t/generic-abstract-class-confusion/7533/4 "2024-12-16T16:36:19Z")

</div>

I think it’s going to be tricky given `Event` itself is generic. Might be easiest to have another parent type like `AbstractEvent` or `EventBase` that isn’t generic such that you can do like `[some_event] of AbstractEvent` to tell the compiler its an array of _any_ event that is a child of this parent type, regardless of generics.

---

<div class="post-metadata">

**Author:** ![dsisnero](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/dsisnero/32/1843_2.png) [@dsisnero](https://forum.crystal-lang.org/u/dsisnero)\
**Post date:** [December 16, 2024, 8:50pm UTC](https://forum.crystal-lang.org/t/generic-abstract-class-confusion/7533/5 "2024-12-16T20:50:10Z")

</div>

How can I run the code in Crystal playground and include a link?

---

<div class="post-metadata">

**Author:** ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)\
**Post date:** [December 16, 2024, 8:50pm UTC](https://forum.crystal-lang.org/t/generic-abstract-class-confusion/7533/6 "2024-12-16T20:50:42Z")

</div>

Should just be able to paste your code into [Carcin](https://play.crystal-lang.org/#/cr), hit `Compile & Run` button, then copy/paste the URL here.

---

<div class="post-metadata">

**Author:** ![dsisnero](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/dsisnero/32/1843_2.png) [@dsisnero](https://forum.crystal-lang.org/u/dsisnero)\
**Post date:** [December 16, 2024, 9:00pm UTC](https://forum.crystal-lang.org/t/generic-abstract-class-confusion/7533/7 "2024-12-16T21:00:52Z")

</div>

Thanks @Blacksmoke16 for your quick replies!  
Can anyone help to get this code [Carcin](https://carc.in/#/r/hill) or something similar to compile?

( I am trying to begin an exploration of concurrent ml ideas - Event abstraction where they the events are lazy - not run until they are synced - right now each type has an explicit sync method but eventually I want to make it implicit and add a correct scheduler implementation - but I am getting stuck at the beginning of my exploration)

---

<div class="post-metadata">

**Author:** ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)\
**Post date:** [December 16, 2024, 9:13pm UTC](https://forum.crystal-lang.org/t/generic-abstract-class-confusion/7533/8 "2024-12-16T21:13:53Z")

</div>

Seems to time out, but [Carcin](https://carc.in/#/r/hilw) compiles at least. Key things I did were:

1. Make `Event(T)` extend `BaseEvent`
2. Change all the concrete event types to extend `Event(T)`
3. Set `ChooseEvent` initialize to be `@events : Array(BaseEvent)`
4. Use `of BaseEvent` when passing the array to `ChooseEvent.new`

---

<div class="post-metadata">

**Author:** ![dsisnero](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/dsisnero/32/1843_2.png) [@dsisnero](https://forum.crystal-lang.org/u/dsisnero)\
**Post date:** [December 16, 2024, 9:41pm UTC](https://forum.crystal-lang.org/t/generic-abstract-class-confusion/7533/9 "2024-12-16T21:41:59Z")

</div>

Thank you! I will work on it now that it is compiling
