Instance variable as parameter in initialize can be accessed without the @ prefix

The output of the following code leaves me a little confused!

class Test
  def initialize(@value : String = "abcd")
	puts value ## without @ instance variable prefix char
  end
end
Test.new # => abcd

I guess it is Crystal’s syntactic sugar for initialization of instance variables that allows this, but nevertheless shouldn’t it raise an exception?

What would be the reason to prevent it? I’m pretty sure:

def initialize(@value : String = "abcd")
  puts value
end

gets re-written to

def initialize(value : String = "abcd")
  @value = value
  puts value
end

So it technically does exist.

Yes, that’s what I think too, but I find it a bit weird anyway.

Yes, ivar parameters are exposed as local variables.
One reason for this is that the parameter may have a type restriction that’s different from the ivar. For example when the ivar is nilable, but the parameter is not, the local variables has the same non-nil type.
Another use case is concurrency: When the method reads the ivar, it may have a different value than what was passed to the method call when it was assigned from a different fiber in the mean time.

4 Likes