Karim Belabas on Wed, 03 Oct 2007 15:05:37 +0200


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

variable scope in GP


Hi all,

  this week-end I spent some time documenting 

* the new my() declarations [ lexically scoped variables ], and 

* the change of paradigm, from dynamic to lexical scoping, for variables
having implicitly local scope [ names of function parameters, names of
loop/summation indices ].

N.B. If the above items don't make sense to you, please update from CVS
(2.4.2 series) and check sections 2.5 and 2.6 of the user's manual.
( If it still does not make sense after that, please ask questions and
propose corrections ! )


The change has *far reaching* consequences, which Bill alluded to in
his earlier messages. The most important ones:

1) If you were used to local(), you almost certainly want to use my() in
its place. If you made essentially trivial use of local(), e.g. without
having bothered to check the documentation and warnings therein, chances
are that your scripts will still work. But, still, see 2): local() is now
deprecated unless you know *exactly* what you're doing.

2) If you hit bizarre bugs in your scripts, check whether you were not
making use of the following "feature":
  
  f(bnf) = ...; g(); ...

  g() = ... use bnf ...

Using dynamic scoping [old], g() called within f() had access to the
'bnf' parameter given to f(), since control flow had not yet left the
scope of f's body.   [ Of course, calling g() from outside f had access
to a different 'bnf'... ]

Using lexical scoping [current], f's bnf is now private to the block of
program text which is f's body, and g() is now accessing some global 'bnf'

Same problem with 'loop indices'

  g() = ... use i ...
  for ( i = 1, 10, g() )

With the new behaviour, g() has no access to the loop index 'i'.

A quick patch for problems of the above kind, without trying to fix the
underlying code, is to use the following trick:

  f(bnf) = local(bnf = bnf); ...; g(); ...

[ a new dynamically scoped 'bnf', initialized to the value of the
lexically scoped 'bnf' passed as a function parameter; g can access the
former ]


3) The debugging facilities offered by trap() and break loops have been
drastically reduced: lexically scoped variables are not accessible to
the break loop [ which is evaluated in a different scope ].

In fact names of lexical variables disappear during the compilation
phase (since we know at that time where to find their values), the
compiled code doesn't know anything about them.

4) For the same reason, 'eval' has become less powerful since it can't
access lexically scoped variables:

  ? my(x = 1); eval("x")
  %1 = x

since the lexical 'x' disappears during compilation, 'eval'uation occurs
too late. Of course

  ? local(x = 1); eval("x")
  %1 = 1

still works, and so does the even more cryptic

  ? my(x = 1); local(x = x); eval("x")


Besides the backward compatibility problems, which should remain limited,
items 3) and 4) are bad news; they currently don't seem easy to fix.

Please test and experiment !

Have fun,

    K.B.

P.S: Two other sources of obscure bugs have been mentionned, which it
would be desirable to address, at the cost of breaking backward
compatibility in a more severe way:

1) Remove the possibility to abreviate f() to f.

2) Initialize new variables to "free variables" not to 0.

-- 
Karim Belabas                  Tel: (+33) (0)5 40 00 26 17
Universite Bordeaux 1          Fax: (+33) (0)5 40 00 69 50
351, cours de la Liberation    http://www.math.u-bordeaux.fr/~belabas/
F-33405 Talence (France)       http://pari.math.u-bordeaux.fr/  [PARI/GP]