Why are these not equal?
['a'].each_with_object('b'){|x,memo| memo << x}
=> "ba"
['a'].each_with_object('b', &:<<)
=> "b"
I thought that the second is just a syntactically sugarized version of the first.
Why are these not equal?
['a'].each_with_object('b'){|x,memo| memo << x}
=> "ba"
['a'].each_with_object('b', &:<<)
=> "b"
I thought that the second is just a syntactically sugarized version of the first.
Symbol#to_proc
returns a Proc
instance of arity -1
:
:<<.to_proc.arity
#⇒ -1
That said, it will silently accept any number of arguments, then basically call args.first.method(self).to_proc
and pass the result of the above as codeblock parameter to the caller. That is why ['a'].reduce('b', :<<)
works as you expected: reduce
’s first block argument is memo
, and
'b'.method(:<<, 'a')
returns "ba"
string.
Your code works the same way:
arr = ['a']
arr.each_with_object('b', &:<<)
arr
#⇒ ['ab']
You’ve just expected the wrong receiver for String#<<
method. In this case, the receiver is an array element, since it’s passed to the block as the first argument. Look:
arr = ['a', 'b']
arr.each_with_object('z', &:<<)
arr
#⇒ ['az', 'bz']
memo
itself stays untouched and returned as a result of call to each_with_object
. You might even have it frozen
and the code will still work.
That said, there is no way to achieve the functionality you requested with syntactic sugar using Symbol#to_proc
and each_with_object
.
The returned object is the first argument passed to each_with_object
. In the first example, this first object "b"
is appended with "a
", which is returned. In the second example, the element of the receiver "a"
is appended with the first argument "b"
, but nothing happens to the first argument.