Point = Data.define(:x, :y)
p1 = Point.new(1, 2) #=> #<data Point x=1, y=2>
… what would you expect to be Data#initialize signature?
I was confused why Data#initialize was relevant to the question instead of Point#initialize. It would be helpful to give the reader the necessary background knowledge that Data.define returns a class that inherits from Data and that doesn’t have an overridden #initialize instance method:
p Point.ancestors
# [Point, Data, Object, Kernel, BasicObject]
p Point.instance_method(:initialize)
# #<UnboundMethod: Data#initialize(*)>
p Point.instance_method(:initialize) == Data.instance_method(:initialize)
# true
That’s why Data#initialize is relevant.
… the [Data#initialize] signature is actually this:
def initialize(x:, y:)
end
That can’t be correct. That could only be true if Point = Data.define(:x, :y) redefined Data#initialize. That new definition of Data#initialize would break initialization of any other Data subclasses, such as MyComplex = Data.define(:real, :imaginary).
I wondered if you had meant to ask about the signature of Point#initialize instead of Data#initialize. However, that can’t be what you meant either because the output above shows that Point.instance_method(:initialize) == Data.instance_method(:initialize).
As far as irb can tell, Point#initialize and Data#initialize take variable parameters:
>> pi = Point.instance_method(:initialize)
=> #<UnboundMethod: Data#initialize(*)>
>> pi.source_location # “returns … nil if this method was not defined in Ruby (i.e. native)”
=> nil
>> pi.arity # “for methods written in C, returns -1 if the call takes a variable number of arguments”
=> -1
>> pi.parameters
=> [[:rest]]
You can check it by redefining initialize …
Point = Data.define(:x, :y) do
def initialize(...)
# …
end
end
The docs for Data say “::define method accepts an optional block and evaluates it in the context of the newly defined class.” Thus, the above code redefines Point#initialize, not Data#initialize.
I was confused why Data#initialize was relevant to the question instead of Point#initialize
Yeah, writing here Point#initialize would be clearer, thanks. It was just a habitual slip (because I knew that Point#initialize, if not redefined, would be Data#initialize
the [Data#initialize] signature is actually this:
…
That can’t be correct.
Yes, again, what I meant here is Point#initialize, and saying it is “actually this” is wrong, it is rather “effectively this”, e.g. behaves like this. Though, as a method defined in C, its declared signature is “give me everything, I’ll check it internally”.
Thank you for valuable remarks, I’ll adjust the post!
This is somewhat unexpected (and was already several times reported as a bug in the official tracker
The assumption that this is unexpected fascinates me.
My work at #{dayjob} involves regular ruby mentorship and I find that neither very new nor very experienced developers would find this unexpected. There is, however, very much a middle group who assume everything in ruby-like languages is a bodge of arrays and dicts under the hood.
I’m always curious about the relative size of these developer populations as it affects how we do code reviews and explanations. I wonder where this comes from.
I was confused why
Data#initializewas relevant to the question instead ofPoint#initialize. It would be helpful to give the reader the necessary background knowledge thatData.definereturns a class that inherits fromDataand that doesn’t have an overridden#initializeinstance method:That’s why
Data#initializeis relevant.That can’t be correct. That could only be true if
Point = Data.define(:x, :y)redefinedData#initialize. That new definition ofData#initializewould break initialization of any otherDatasubclasses, such asMyComplex = Data.define(:real, :imaginary).I wondered if you had meant to ask about the signature of
Point#initializeinstead ofData#initialize. However, that can’t be what you meant either because the output above shows thatPoint.instance_method(:initialize) == Data.instance_method(:initialize).As far as
irbcan tell,Point#initializeandData#initializetake variable parameters:The docs for
Datasay “::definemethod accepts an optional block and evaluates it in the context of the newly defined class.” Thus, the above code redefinesPoint#initialize, notData#initialize.Yeah, writing here
Point#initializewould be clearer, thanks. It was just a habitual slip (because I knew thatPoint#initialize, if not redefined, would beData#initializeYes, again, what I meant here is
Point#initialize, and saying it is “actually this” is wrong, it is rather “effectively this”, e.g. behaves like this. Though, as a method defined in C, its declared signature is “give me everything, I’ll check it internally”.Thank you for valuable remarks, I’ll adjust the post!
The assumption that this is unexpected fascinates me.
My work at #{dayjob} involves regular ruby mentorship and I find that neither very new nor very experienced developers would find this unexpected. There is, however, very much a middle group who assume everything in ruby-like languages is a bodge of arrays and dicts under the hood.
I’m always curious about the relative size of these developer populations as it affects how we do code reviews and explanations. I wonder where this comes from.
then… it’s a bug. Once or twice? I get it… But several times is definitely a bug.