Open Christopher-Chianelli opened 4 years ago
Hi Christopher,
Thank you. You are correct. The binding of the variable in for
loop is presently broken, and unfortunately, is likely to remain so for a few months 😦. To illustrate, the following currently works (at least in interpreted mode):
I := 6
print "The factorial of ", I, " is ", I!
But with a for
loop, it does not work (yet, or no longer, depending on how you look at it).
For the longest of time, for
loops have been a problem in the language because one of their arguments is created. In your example, a variable named I
needs to be created, and if you define your own for
loop, the scope of that variable used to be very unclear. The current definition, found here, creates a local variable Var
that does not modify the incoming parameter. It currently looks like this:
for Var in Low..High loop Body is
Var := Low
while Var < High loop
Body
Var := Var + 1
That's very naive for a number of reasons One of them is Var := Var + 1
, which only works for integer types. In your case, that's not a problem, but for I in 'A'..'C'
would be broken by that. But there is nothing in that code that explains how Var
would be anything but a local parameter. Which it presently is.
Earlier versions of the code have been working around this by special-casing it in the compiler (e.g. was the case in Tao3D), or trying to have a special annotation to the parameter (e.g. I:var integer
, etc), which I was never happy with. All these variants broke under some common scenario. For example, you want Var
to be visible in the while
conditions, but to be visible in Body
under some other name, I
in your case.
I believe I finally found the "right" way to express this, which is documented here, where the code will look like this:
for N:name in R:[range of discrete] loop Body is
loop_context is
[[N]] : R.type := R.first
LoopVar is loop_context.[[N]]
while LoopVar <= R.last loop
(loop_context) (Body)
++LoopVar
Here are the things that are broken for this to work:
name
type to preclude evaluation of the associated namerange of discrete
is not available yet, because I just introduced (in the documentation only) the discrete
type, and a generic range
was never implemented since the XL2
times (circa 2005-ish)[[N]]
(a meta box in a declaration context to inject a name) is not implemented at allLoopVar
declaration yet (whether you can modify through it). There are pros and cons.(loop_context) (Body)
is supposed to be a scope injection of the loop_context
scope while evaluating Body
. While some support for this kind of prefix scoping operator made it to the interpreted version about one year ago, it's insufficient and broken in other cases.So this explains why I believe it will be a while until the for
loop actually works as intended.
Thanks a lot for reporting it, though. I will keep the issue open, and if/when I finally get the for
loop to do the right thing while being written the right way, which will be a big victory, you will know 😄 .
In order to show what some earlier implementations of the for
loop used to look like, see this commit
- I'm not entirely sure about the
LoopVar
declaration yet (whether you can modify through it). There are pros and cons.
This can have something to do with immutability. Feel free to look at V lang (doc with examples) as a modern take on that (I like the "immutable by default" which I'm not sure XL could easily express (I have a feeling "mutable by default" should be doable in XL, but that partially defeats the added value of immutability). On the other hand I'm not exactly sure whether immutability is that useful in non-imperative style of programming.
So if I understand the problem with LoopVar
correctly then the pros and cons
you're mentioning seem to be rather something XL should factor out and let the programmer choose instead of letting the standard library (or "the language" if you want) decide it up front.
Just my 2 cents :wink:.
The README shows the following code for a program that compute the factorial of 1 to 5:
I expect this to print:
However, the following is printed instead:
Environment:
gcc:latest
Docker image (Debian) Occurs in both interpreted (xl -i file.xl
) and compiled (xl file.xl
) forms.