Consider the following script:
<script>
set echo off
set messages off
function foo(list X)
printf "\nInside function foo:\n"
loop foreach i X -q
printf "$i\n"
end loop
end function
function bar(list X)
printf "\nInside function bar:\n"
loop foreach i X -q
printf "%s\n", varname(i)
end loop
end function
nulldata 10
x1 = normal()
x2 = normal()
list X = const x1 x2
printf "\nOutside a function:\n"
loop foreach i X -q
printf "$i\n"
end loop
foo(X)
bar(X)
</script>
With current CVS, with PROTECT_LISTS=1, it yields:
<output>
Outside a function:
const
x1
x2
Inside function foo:
const
2
3
Inside function bar:
index
x1
x2
</output>
There are several points I'd like to raise: bear with me, this is going to
be neither short nor painless.
Looking at the output of "foo", clearly the constant is treated
specially, which should not happen. This also affects the output of "bar",
in which varname(i) becomes varname(const)=varname(1)="index"
Even if the above particular asymmetry is removed, another one becomes
evident: foreach loops inside functions behave differently from those
outside. In the latter case, "$i" yields a string; in the former, an
integer. This has all sort of weird consequences: for example, a statement
like "genr $i_xxx = normal()" is legal outside a function but becomes
illegal inside, since identifiers cannot start with numbers.
A possible way out would be to endow variables passed through lists with
local aliases, like for example "X->const", or "X.x1", in which we
use
some "illegal" marker ("->" or "." in the above examples)
to make sure
that no name clashes inside functions can occur.
This isn't trivial to implement, and has the added disadvantage that you
may end up with monsters like "LongNameList.VeryVerboseVariable", but the
alternatives are not very palatable either: with the new mechanism (which,
I repeat, I consider indispensable), either we're prepared to live with a
syntax inconsistency (terrible) or we change the meaning of $i in foreach
loops outside functions. This would be a huge backward-incompatible change
(are you there, Sven?). In other words, if the "local name" solution (plan
A) proves impractical, I propose to extend the varname() mechanism for
retrieving variable names to all foreach loops (plan B). The number of
existing scripts that will be broken if plan B is carried forward is
doubtlessly enormous, but I think it would be a sad necessity.
Now, the question is: what should our policy be?
Riccardo (Jack) Lucchetti
Dipartimento di Economia
Università Politecnica delle Marche
r.lucchetti(a)univpm.it
http://www.econ.univpm.it/lucchetti