Compilation error when using an abstract struct with subtypes

I’m no expert in compilers (although, I have an interest in learning in order to improve Crystal).

In my experiments I was attempting to model something and ran into this error which would prevent me from making progress with the particular API that I have in mind.

DOES WORK

abstract struct Errors(T) end
struct Recoverable(T) < Errors(T) end

struct Rand(T)
  @errors : Errors(T)
  
  def initialize(@errors) end
end

puts Rand(Int32).new(Recoverable(Int32).new())

DOESN’T WORK (but the Haskell version of this does)

abstract struct Errors(T) end
struct Recoverable(T) < Errors(T) end

struct Rand(T)
  @errors : Array(Errors(T))
  
  def initialize(@errors) end
end

puts Rand(Int32).new([Recoverable(Int32).new()])

The Haskell version:

import Data.List

data Errors a = Recoverable a | Bug a deriving Show

data Rand a = Rand {
  errors :: [Errors a]
} deriving Show

main = do
  print $ Rand $ [Recoverable "You can recover from this error"]

Surrounding code in backticks makes it read easier. Also including the output/playground links can also be helpful.

Carcin Does what you want tho. See Inheritance - Crystal.

1 Like

Hi @JamesGood626 the problem with your example is that in

puts Rand(Int32).new([Recoverable(Int32).new()]

The [Recoverable(Int32).new()] is of type Array(Recoverable(Int32)) instead of an Array(Errors(Int32)).

You will need to give the compiler a little hint here. One way is

puts Rand(Int32).new([Recoverable(Int32).new()] of Errors(Int32))

The API of Rand could be changed so you don’t need to do that workaround on callsite. For example

abstract struct Errors(T)
end

struct Recoverable(T) < Errors(T)
end

struct Rand(T)
  @errors : Array(Errors(T))

  def initialize(errors)
    @errors = errors.map { |v| v.as(Errors(T)) }
  end

end

puts Rand(Int32).new([Recoverable(Int32).new()])

On missuses the compiler errors would be more cryptic though.

puts Rand(Int32).new([0])

# 11 | @errors = errors.map { |v| v.as(Errors(T)) }
#                                 ^
# Error: can't cast Int32 to Errors(Int32)

Check FAQ · crystal-lang/crystal Wiki · GitHub for some further examples

It’s been awhile, but I wanted to say thank you for your help. Shortly after you posted this I did manage to get it working. I just haven’t been programming much lately.