I support all that you have written, as I have been bitten by this
inconsistency in the past (in a less serious way than you).

Can I add some simple observations:

(1) When you write     a,b = c

then Ruby has to assume you mean either:

             (i)       a,b = c,nil
         or  (ii)      a,b = *c

In the simple assignment case, both can be achieved explicitly; I guess Ruby
chooses (ii) as "more likely to be what you meant", but you don't actually
need that magic because you can achieve it youself using "*". Similarly for
a = b,c:

             (iii)     a,dummy = b,c
             (iv)      *a = b,c

(2) The problem with Hash#each is that for hashes to be enumerable they must
contain a list of individual "things", and a "thing" is chosen here to be a
[key,value] pair.

So Hash#each does      yield [k,v]

and the block we pass in takes |thing| as a parameter. Now, we'd like to be
able to do
          myhash.each { |key,value| ... }

but we need magic for that. We can't achieve it using "*", because we'd have
to change the 'yield' statement to do that: yield *[k,v], or yield k,v. In
other words, we'd have to modify the source code of the iterator itself.

NOW: if it's *only* Hash#each which is the problem here, then one Ruby-2.0
solution is to add a new iterator to Hash, or just redefine

         Hash#each_pair        -->  yield k,v

This iterator already exists in the language, so you could make your code
backwards-compatibile by using it where you want to do { |key,value| ... }

But it seems to me a better option would be to have a way at the *receiver*
of specifying that you want the argument 'exploded', and it turns out that
Ruby already has this:

         myhash.each { |(key,value)| ... }

Tested in 1.8.1:

      def foo
        yield [1,2], [3,4]
      end

      foo { |a,b| p a,b }
[1, 2]
[3, 4]
=> nil

      foo { |x,(y,z)| p x,y,z }
[1, 2]
3
4
=> nil

So perhaps all we need to do, for ruby-2.0 at least, is keep this mechanism
and get rid of the rule which says "if single argument is an array then
auto-expand it" completely.

And then, maybe we should persuade people to write
      (a,b)=c
rather than
      a,b=*c

(although exploding at the sender, i.e. "yield *foo" and "bar(*foo)", are
still useful constructs)

Applying this to your example:

>      There are two ways that the discrepancy could be resolved: either
> the behavior of yield could be changed, or that of Proc#call.  If the
> former path had been taken
...
> the prior behavior could have been reproduced (if desired) by writing:
>         
>         def foo
>             yield(*[:key, :value])
>             end
>         foo {|k, v| p [k, v]}     #[:key, :value]

Without changing the definition of foo, you could just have called it as

          foo {|(k,v)| p [k, v]}    #[:key, :value]


(3) It may be possible to keep Ruby's automagic exploding of arguments, if
we limit it to cases where there is no ambiguity. I am thinking of:

  - the sender passes a single array value;
  - the receiver REQUIRES two or more arguments.

This is unlike def foo(head,*rest) or proc {|head,*rest| ... }, where it can
take _one_ or more arguments, so the rule would not apply.

This might be a solution for 1.8.2, where you want to be backwards
compatible. At least, Hash#each { |key,value| ... } would continue to work.
But it still wouldn't be consistent, unless you also applied it also to
method calls (which would be dubious, IMO)

Regards,

Brian.