Feature #19830
openAllow `Array#transpose` to take an optional size argument
Description
One benefit of supplying an initial value to Enumerable#inject is that it avoids an annoying edge case when the collection is empty:
>> [1, 2, 3].inject(:+)
=> 6 # good
>> [].inject(:+)
=> nil # bad
>> [].inject(0, :+)
=> 0 # good
A similar edge case exists for Array#transpose:
>> [[1, :a], [2, :b], [3, :c]].transpose
=> [[1, 2, 3], [:a, :b, :c]] # good
>> [].transpose
=> [] # bad
Although no explicit nil is produced here, the subtle problem is that the caller may assume that the result array contains arrays, and that assumption leads to nils in the empty case:
>> [[1, :a], [2, :b], [3, :c]].transpose.then { _2.join }
=> "abc"
>> [].transpose.then { _2.join }
undefined method `join' for nil:NilClass (NoMethodError)
If we allow Array#transpose to take an optional argument specifying the size of the result array, we can use this to always return an array of the correct size:
>> [[1, :a], [2, :b], [3, :c]].transpose(2)
=> [[1, 2, 3], [:a, :b, :c]] # good
>> [].transpose(2)
=> [[], []] # good
By avoiding an unexpectedly empty result array, we also avoid unexpected downstream nils:
>> [[1, :a], [2, :b], [3, :c]].transpose(2).then { _2.join }
=> "abc"
>> [].transpose(2).then { _2.join }
=> ""
Here is a patch which adds an optional argument to Array#transpose to support the above usage: https://github.com/ruby/ruby/pull/8167
Something similar was requested eleven years ago in #6852. I believe this feature addresses the problem expressed in that issue without compromising backward compatibility with existing callers of #transpose.