0

I have the following two methods, which I believe should have the same behaviour disregarding their names:

def a=(*params)
  params
end

def b(*params)
  params
end

But when in fact I use them:

a=(1) # => 1
b(1) # => [1]
(a=1) == b(1) # => false

while interestingly:

(a=1,2) == b(1,2) # => true

Why isn't their behaviour the same?

Edit: forgot to wrap the above in a class / call with self. which accidentally produces the same behaviour but for a different reason. It has been pointed out in the answers.

thisismydesign
  • 21,553
  • 9
  • 123
  • 126
  • 2
    I rolled back your edit because you changed the question after getting an answer from mudasobwa that crucially points out something that is related to the part that you changed. Don't change your questions at that timing. – sawa Sep 08 '17 at 12:51
  • Sorry, forgot to add `self.` while I was trying to provide a minimal example where the issue can be reproduced because accidentally it still produced the same issue. Unfortunately this way the question is silly but in the end I did get the answer to my real problem in the answer you're referring to. – thisismydesign Sep 08 '17 at 13:00

2 Answers2

4

It has nothing to do with splat. It's the assignment operator. In ruby, the assignment operator returns the value assigned. The return value from the method is ignored.

So a=1 return 1, not [1].

But, as mentioned by @mudasobwa, you're not even calling the method here. But if you were, that's what would happen (ignoring the return value).

class Foo

  def a=(*params)
    params
  end

end

f = Foo.new

f.a = 1 # => 1
f.a = 1,2 # => [1, 2]

To not ignore the return value, call that setter without using assignment operator.

f.send 'a=', 1 # => [1]
Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
2

The thing is that

a = 1

sets the local variable and does not call your method at all. Try with

def a=(*param)
  puts "I AM HERE"
end

var= methods require an explicit receiver. To call your method, call it with an explicit receiver:

self.a = 1

It still won’t return anything but 1, because assignment methods return the value (the same way as initialize called through MyClass.new returns an instance, no matter what.) But you might check that splat works with:

def a=(*param)
  puts param.inspect
end
self.a = 1
# [1]
#⇒ 1
Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160
  • ah yes, splat most certainly works, even if it looks like it doesn't :) – Sergio Tulentsev Sep 08 '17 at 12:56
  • Forgot to add `self.` while I was trying to provide a minimal example where the issue can be reproduced because accidentally it still produced the same issue. So the take away is "assignment methods return the value, no matter what". Thanks! – thisismydesign Sep 08 '17 at 12:58