Crystal: Subclasses in Proc type

Created on 10 Nov 2016  路  5Comments  路  Source: crystal-lang/crystal

The following (reduced) example:

class Foo
end

class Bar < Foo
end

class Baz < Foo
end

alias ProcType = Proc(Foo)

class Qux
  property test : ProcType

  def initialize(@test)
  end
end

def a
  Bar.new
end

def b
  Baz.new
end

Qux.new(->a)
Qux.new(->b)

produces the following error message:

Error in ./test.cr:27: instantiating 'Qux:Class#new(Proc(Bar))'

Qux.new(->a)
    ^~~

in ./test.cr:15: instantiating 'Qux#initialize(Proc(Bar))'

  def initialize(@test)
  ^

in ./test.cr:15: instance variable '@test' of Qux must be Proc(Foo), not Proc(Bar)

  def initialize(@test)
                 ^~~~~

I'm on Crystal 0.19.4 (2016-10-21) on macOS Sierra 10.12.1

I'm expecting this to work because Bar is a subclass of Foo and ProcType asks for a value of type Foo.

Is this a bug / missing feature or am I just missing something?

bug compiler

Most helpful comment

Just expanding on @RX14:

class Qux
  property test : ProcType

  def initialize(test)
    @test = ->{test.call.as(Foo)}
  end
end

All 5 comments

Yeah, that should probably work (passing a proc with a stronger return type)

Until this is fixed, I found a way to work around this issue:

alias ProcType =  Proc(Foo) | Proc(Bar) | Proc(Baz)

You just have to repeat this for every class / subclass you want to support.

You can also use .as(Foo) as a workaround.

@RX14 true, although you might want to get back Bar or Baz and do the casting just for the Proc.

Just expanding on @RX14:

class Qux
  property test : ProcType

  def initialize(test)
    @test = ->{test.call.as(Foo)}
  end
end
Was this page helpful?
0 / 5 - 0 ratings