Reputation: 644
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
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