Scripsit ille rian CandlerĄ© <B.Candler / pobox.com>:
> In Ruby:
> 
>     l = %w{one two three}
>     l.each do |elem|
>       elem.replace('X' + elem.upcase)
>     end
>     p l
> 
> In other words, you have to mutate the existing element; assigning to 'elem'
> does not replace the element, it simply makes the local variable point
> elsewhere.

Yes, that is exactly the problem.

> There is some Bad Magic going on in the Perl version; somehow $elem is
> aliasing an element of the array, it is not a normal variable at all.

Yes, and that's why I think many languages, including Ruby and Java,
need "pointers". The typical Java workaround is a size-1 array. You can
do the same in Ruby of course... but I wouldn't like it.

Perl, for example, has pointers:

  my $x = 17;
  my $ptr = \$x; # <-- THAT's the thing which is missing in Ruby!
  ${$ptr} = 42;

An alternative would then look like this - they aren't really pointers,
they're one-element containers which can be used similar to other
pointer workaround:

class Pointer
  def initialize(v)
    @pointer_target = v
  end
  def []()
    @pointer_target
  end
  def []=(other)
    @pointer_target = other
  end
end

class PointerArray < Array
  def [](a)
    return super(a)[]
  end
  def []=(a, b)
    return super(a, Pointer.new(b))
  end
end

a = PointerArray.new()
a[0] = "Hello"
a[1] = "World"
a.each() do |x|
  x[] = "*** " + x[] + " ***"
end
p a[0]
p a[1]

# evil - but Ruby handles it nicely:
x = Pointer.new(42)
x[] = x
p x