monomonedula
monomonedula

Reputation: 644

Why doesn't crystal's type inference work on classes as expected?

Why can I define a method like that in Crystal:

def foo(bar): String
  bar.to_json
end

foo({"x" => 1, "y" => 2})

but that kind of type inference doesn't work with classes:

class Foo
  def initialize(bar)
    @bar = bar
  end

  def foo: String
    @bar.to_json
  end
end


Foo.new({"x" => 1, "y" => 2}).foo

and it ends up with

Error: can't infer the type of instance variable '@bar' of Foo

What am I missing about Crystal's type inference and what is the workaround for this?

Upvotes: 2

Views: 158

Answers (1)

Jonne Haß
Jonne Haß

Reputation: 4857

The equivalent class based approach is making the class a generic:

require "json"

class Foo(T)
  def initialize(@bar : T)
  end

  def foo
    @bar.to_json
  end
end


puts Foo.new({"x" => 1, "y" => 2}).foo

Instance variables need their type set in one way or another because lexicographical type flow analysis is much harder and thus slower to do for them. Also classes build the base of your program so typing them as narrow as possible not only makes the compiler's job easier, it also makes them easier to use. Too open type restrictions on instance variables can lead to quite long and confusing error messages.

You can read more at the original proposal introducing the change to require type annotations on instance variables: https://github.com/crystal-lang/crystal/issues/2390

Upvotes: 4

Related Questions