I found some little surprise type inference in class with instance variable and ||=.
Result is it returned same type.
code: https://play.crystal-lang.org/#/r/3aza
class Foobar
def name
@name ||= "anonymous"
end
end
a = Foobar.new
puts a.name #=> anonymous
puts a.name.class # => String
Result is it throwed an exception about
Can't infer the type of instance variable
code: https://play.crystal-lang.org/#/r/3az9
class Foobar
def name
@name ||= default_name
end
def default_name : String
"anonymous"
end
end
a = Foobar.new
puts a.name #=> Exception: Can't infer the type of instance variable
as to variable.Result is it returned same type (same as Test one).
code: https://play.crystal-lang.org/#/r/3azb
class Foobar
def name
@name ||= default_name.as(String)
end
def default_name
"anonymous"
end
end
a = Foobar.new
puts a.name #=> anonymous
puts a.name.class # => String
Both Test one and Test three all missing define type of the instance variable, but it could pass the complier.
type inference at works. looking at https://github.com/crystal-lang/crystal/blob/master/src/compiler/crystal/semantic/type_guess_visitor.cr seem some undocumented rules. for example ||= and .as.
no bug here, works as expected, only not documented.
when literal, as, etc., compiler can guess. when method call, no.
I think we should be able to infer this: the method has a specific return annotation.
It's a consequence of the syntax sugar expansion of @name ||= "anonymous" ~> @name || @name = "anonymous" So there is a literal been assigned and fall into the rule 1.
It is documented at https://crystal-lang.org/docs/syntax_and_semantics/type_inference.html#other-rules
Test two won't work. A subclass might override the method and currently there is no enforcement that the return type should obey the type restriction of the base class. Note that when the method have params the resolution is even more complex/time consuming.
Any suggestion on how to improve discoverability / error message? Otherwise there is nothing to be done.
Thanks for pointing out my mistake @bcardiff.
thanks @bcardiff and @RX14
@bcardiff The error message is already quite comprehensive and details all the cases where implicit type inference can be applied.
Most helpful comment
It's a consequence of the syntax sugar expansion of
@name ||= "anonymous"~>@name || @name = "anonymous"So there is a literal been assigned and fall into the rule 1.It is documented at https://crystal-lang.org/docs/syntax_and_semantics/type_inference.html#other-rules
Test two won't work. A subclass might override the method and currently there is no enforcement that the return type should obey the type restriction of the base class. Note that when the method have params the resolution is even more complex/time consuming.
Any suggestion on how to improve discoverability / error message? Otherwise there is nothing to be done.