Splat parameters behave differently for attribute writers compared to regular method

64 views Asked by At

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.

2

There are 2 answers

1
Sergio Tulentsev On BEST ANSWER

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]
2
Aleksei Matiushkin On

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