Ruby #tap

Bit of Ruby fun. I really like #tap for cleaning up blocks where you assign unnecessary variables. While I admit the following examples don’t all do the same thing I noticed something this morning. The first two should have concatenated the Array and last one oappended. It’s odd that the first two examples returned an empty Array and not [1, 1, 2, 3], or [[1 ], [1, 2, 3]]

2.2.6 :018 > [].tap { |a| a += [1]; a += [1,2,3] }
 => [] 
2.2.6 :018 > [].tap { |a| a += [[1]]; a += [[1,2,3]] }
 => [] 
2.2.6 :019 > [].tap { |a| a << [1]; a << [1,2,3] }
 => [[1], [1, 2, 3]] 

So, the object returned from #tap is always the one you passed in, so for a start is doesn’t return that last thing evaluated in the block. Then you realise a += 1 returns a new object and reassigns the value of a, so it can’t be the original object and therefore you’re concatenating and creating a new object that isn’t returned.