[ZILF] Simple Set Statement in GO Routine Leads to Error

I have some code that is very simple and looks like this:

<ROUTINE GO ()
  <SET A 10>
>

That does not compile.

The error returned is:

I’m not sure why this is an issue. The expression

<SET A 10>

does work just fine in the REPL.

Ah, okay, so maybe I have an answer that I need to document somewhere. It looks like you have to “declare” the local variable with “AUX”.

Someone correct me if I’m wrong.

So I tried this:

<ROUTINE GO ("AUX" A)
  <SET A 10>
>

That leads to a much different error:

So that’s good to know but it would also be good to confirm just in case I’m going way off the reservation here.

There are two separate issues at play here.

First, as you surmised, you can’t use local variables in a ZIL routine unless you’ve declared them first. Marking them “AUX” is optional but standard (it indicates that you’re not expecting the caller to fill these in with function arguments, they’re just for your own use inside the routine).

Second, the GO routine is special. It’s not actually quite a routine, in that it isn’t called by any other routine, and doesn’t return a value. Instead, GO provides a raw block of code that’s executed when the VM starts up. Since it’s not a routine, it doesn’t (and can’t) have local variables.

So the conventional thing to do is to write a very simple GO which just calls another routine (Inform calls it Main, I think ZIL usually calls it MAIN) and then shuts down the VM. You can then put all your code in MAIN and use whatever local variables you like, since it’s a normal routine in every way.

Thanks for the context! Yeah, how I framed the example in my documentation is as such:

<ROUTINE GO ()
  <INIT>
>

<ROUTINE INIT ("AUX" A)
  <SET A 10>
>

I also do realize a lot of people may not even encounter these issues. But I tend to learn – and document – by literally starting from ground zero, building really simple stuff and then seeing where the cognitive friction hits.

I’m calling this document LEARN_ZIL and I’m seeing how much of my other material I incorporate into it.

Interestingly, although version 6 (yzip) does have a starting routine, which allows local variables, zilf seems to still disallow them.

This is a difference between MDL and ZIL.

In MDL:

  • Variables never need to be declared; any atom can potentially have local and/or global values associated with it using SET and SETG.
  • <SET A 10> finds (or creates) the current local binding of A and stores 10 in it.
  • .A (<LVAL A>) finds the current local binding for A and returns its value, raising an error if there is no binding (<BOUND? A> is false) or the binding has no value (<ASSIGNED? A> is false).
  • When you call a MDL function that has A in its parameter list (technically a binding list), a new local binding for A is pushed onto the stack, and possibly assigned a value: the corresponding argument that was passed in, or the default value, if applicable. The binding is popped off when the function returns.
  • Neither SET nor LVAL care whether the binding was created by the currently executing function - in this dynamic binding, you can access the “local variables” of functions higher up on the call stack, as long as those atoms haven’t been given new bindings in the meantime.
  • You can use SET even at the top level, because the concept of local bindings isn’t tied to functions.

In ZIL (that is, in ROUTINEs), they behave more like local variables in other languages:

  • Each one has to be declared first, because it has to be assigned a specific slot in the current routine’s call frame.
  • There’s no way for one routine to access the local variables in another routine’s call frame.
  • You can’t use SET at top level, because local variables don’t exist without call frames.

:grimacing:

Not quite optional - without marking them "AUX" (or "OPT"), you’ll get an error if you try to call the routine without them.

Oops. Filed as ZILF-210.