Karim BELABAS on Tue, 2 Jul 2002 02:07:19 +0200 (MEST)

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

Re: Bug in parsing of local()

On Mon, 1 Jul 2002, Ilya Zakharevich wrote:
> ? ff(x)=local(y=x);x=177;print(y)
> ? ff(12)
> 12
> ? gg(x)=local(y=x);x='x;x=177;print(y)
> ? gg(12)
> 177
> I think the answers should be the same...  The problem may be due to
> the following difference in the assignment of variables and
> parameters:
>   for (i=0; i<narg; i++) copyvalue(*p++, *arg++);
>   for (i=0; i<nloc; i++) pushvalue(*p++, make_arg(*loc++));
> (the difference between copy and push).  And what make_arg() magic is doing
> there?

1) make_arg(): parameters with default values are evaluated when the function
is called [ was: when the function is defined (long time ago), see COMPAT-2.2 ]

Hence default values are really formal expressions [character strings], which
are evaluated to bona fide GENs by make_arg().

[ btw, make_arg() was unnecessarily complicated, I simplified it ]

2) copy: clone the value
   push: store the address of the value

Values of arguments are cloned, values of local variables are pushed (the
initial value is assumed not to vary while we evaluate the function).

3) In both cases above, I would expect SEGV (but then, I know how the thing
is implemented...). Strangely enough, I couldn't produce one in a
deterministic way.

This is a long standing problem related to TODO entry

  5  life of GP variables too short in pathological cases:

     v = [0,0]; v + [v=0,v=0] --> SEGV

     u = Mod(x*Mod(1,2), polcyclo(25)*Mod(1,2));
     sum(i=1,4,u=u^32) --> SEGV

I've modified the [string to GEN] routines (lisexpr and variants) so that
they never return a clone: it is almost certain that this is a variable
value, which may be destroyed anytime [we don't have reference couting].

The patch fixes all the bug mentioned above. I'm not 100% sure it fixes all
instances of the problem.

It shouldn't be detrimental to efficiency in any case, please check your
GP scripts [esp. the badly written ones]...



P.S: we have a major performance problem with argument passing. It would be
so much simpler if there were a way to pass variables by reference.
Currently, in user functions, it's much more efficient to use global
variables than to pass structs as arguments [ the latter are cloned; if they
are large and the routine is used often, we're dead ].

It's been in my personal TODO list for a long time to check whether a
function definition like

  f(&x, y) = ...

would break anything. Here, x is a reference, y is a value. Modifying x in
the function body would modify x in the calling frame. Modifying y would
modify a copy (current behaviour).

Not sure about the calling, syntax. Maybe f(x,y), or f(&x, y) to emphasize
we're passing a reference. Probably the former.

It would be very easy to add, would not introduce ambiguities, and would be
_very_ useful. The most important use would be that it would at last be
possible to write (relatively) efficient user functions without using global

Karim Belabas                    Tel: (+33) (0)1 69 15 57 48
Dép. de Mathematiques, Bat. 425  Fax: (+33) (0)1 69 15 60 19
Université Paris-Sud             Email: Karim.Belabas@math.u-psud.fr
F-91405 Orsay (France)           http://www.math.u-psud.fr/~belabas/
PARI/GP Home Page: http://www.parigp-home.de/