Why do #each_with_object and #inject switch the order of block parameters?

# each_with_object and # inject can both be used to create a hash.

For instance:

matrix = [['foo', 'bar'], ['cat', 'dog']] some_hash = matrix.inject({}) do |memo, arr| memo[arr[0]] = arr memo # no implicit conversion of String into Integer (TypeError) if commented out end p some_hash # {"foo"=>["foo", "bar"], "cat"=>["cat", "dog"]} another_hash = matrix.each_with_object({}) do |arr, memo| memo[arr[0]] = arr end p another_hash # {"foo"=>["foo", "bar"], "cat"=>["cat", "dog"]} 

One of the key differences between them: #each_with_object keeps track of memo throughout the iteration, and #inject sets memo equal to the value returned by the block at each iteration.

Another difference is the order or parameters of the block.

Is there any intention to communicate here? It makes no sense to change the parameters of a block of two similar methods.

+5
source share
1 answer

They have a different pedigree.

  • each_with_object was added in Ruby 1.9 in 2007.
  • inject returns to Smalltalk in 1980.

I assume that if a language was designed with both methods from the very beginning, they most likely expect the arguments in the same order. But this is not so. inject exists from the very beginning of Ruby, whereas each_with_object was added only after 10 years.

inject expects arguments in the same order as Smalltalk inject:into:

 collection inject: 0 into: [ :memo :each | memo + each ] 

which performs the left fold. You can imagine the collection as a long strip of paper that folds to the left, and the sliding window of the fold function is always the part that has already been folded, as well as the next element of the remaining paper strip

 # (memo = 0 and 1), 2, 3, 4 # (memo = 1 and 2), 3, 4 # (memo = 3 and 3), 4 # (memo = 6 and 4) 

According to the Smalltalk convention, this made sense, since all the initial methods in Enumerable were taken from Smalltalk, and Matz did not want to confuse people familiar with Smalltalk.

And no one can predict that this will happen in 2007 when each_with_object was introduced in Ruby 1.9, and the order of the arguments reflects the lexical order of the method name, which is equal to each ... object .

And so these two methods expect arguments in different orders for historical reasons.

+4
source

Source: https://habr.com/ru/post/1263143/


All Articles