"Rudolf Polzer" <denshimeiru-sapmctacher / durchnull.de> schrieb im
Newsbeitrag
news:slrnblprei.b2n.denshimeiru-sapmctacher / message-id.durchnull.ath.cx...
> Scripsit illa aut ille ?Karsten Meier? <discussion / internetlabor.de>:
> > I'm working on the ruby section of the pleac project,
> > (http://pleac.sourceforge.net) because I think a good way to learn a
new
> > language is trying to explain it to somebody else.
> > There are a few hundred code snippnets from the famous perl cookbook,
> > and one of it is perls local function:
> > You can give a global variable inside a block a new value. This is
> > slightly different from normal local variable, because it really
changes
> > the global variable. I think it is sometimes even useful, when you
need
> > to change the predefined global variables, but want to automatically
> > restore them after you are done.
>
> Not really.
>
>   rpolzer@katsuragi ~ $ perl -e '
>     $a = 17;
>     $p = \$a;
>     {
>       local $a = 42;
>       $q = \$a;
>     }
>     print "$a, $p<$$p>, $q<$$q>\n";
>   '
>   17, SCALAR(0x812e798)<17>, SCALAR(0x812155c)<42>
>
> It's more than Save&Restore of the variable contents. It saves and
> restores the variable pointers in the symbol table. In fact, both
> $a were DIFFERENT variables, which justifies the "declaration-style
> syntax" of local.

But perl and ruby treat variables differently.  Especially in perl there
can be two instances that carry the value 42 while in ruby this is always
one instance that is referenced.  If you would use the proposed solution
and assign another global from the temporarily changed global you could
produce similar output to your perl variant.  (Without the hex addresses,
of course)

My concern would rather be that the proposed solution (apart from the
exception thingy that you fixed) would not work for multiple threads.  As
far as I remember the perl's "local" does dynamically scoping, i.e., it
affects only methods invoked from the method that contains the "local". In
a single threaded environment this is no difference, but in MT
environments as ruby this does make a significant difference.  Thus a
thread safe ruby solution should rather include Thread[] and Thread[]=,
which unfortunately would make the syntax more ugly.

Technically this could be a solution, but it does not look nice which
certainly defys the original intention:

def local(sym, val)
  ar = ( Thread.current[sym] ||= [] )
  ar.unshift( val )

  begin
    yield
  ensure
    ar.shift
  end
end

def get_local(sym)
  ar = Thread.current[sym]
  raise "#{sym} undefined" unless ar && !ar.empty?
  ar[0]
end

def set_local(sym, val)
  ar = Thread.current[sym]
  raise "#{sym} undefined" unless ar && !ar.empty?
  ar[0]= val
end

# usage, thread safe
local :foo, 20 do
  puts get_local( :foo )

  local :foo, 42 do
    puts get_local( :foo )
  end
end

Regards

    robert