Gauche
Gauche copied to clipboard
Evaluation order and error messages
$ gosh -r 7
gosh[r7rs.user]> (receive (a b) (values 1 2) (list a b))
*** ERROR: unbound variable: b
The real error is that receive
macro is not defined in R7RS mode:
gosh[r7rs.user]> receive
*** ERROR: unbound variable: receive
I presume the operands are evaluated right-to-left. Since none of receive
, a
and b
are defined, b
is the first to cause an error. It would be more obvious if the first operand was evaluated first, because if it's supposed to be a macro, that macro may be intended to bind the rest of the operands.
Another example:
$ gosh -r 7
gosh[r7rs.user]> (use gauche.process)
*** ERROR: unbound variable: gauche.process
This has been brought up before. It does perplex users. The thing is that Gauche VM is a stack machine and evaluating the operator last is the optimal (otherwise we need extra stack operation or extra binding check.)
One solution to make it less confusing without sacrificing performance is to make error reporting more smart, e.g. in the first example, let it report like:
*** ERROR: unbound variable: b
while evaluating (a b)
while evaluating (receive (a b) ....)
This is a bit of a hack, but could you add an extra evaluation in case of error? I.e.:
- It would start by evaluating
b
thena
as it does now. - If one of those fails, and the head is a symbol (e.g.
receive
), and that symbol is not bound, then it shows an error about that. - It the evalutation fails but the head is not an unbound symbol, it shows an error about
b
.
If b
is replaced by some complex expression that succeeds, but a
fails, you'd probably have to prove that b
does not mutate the head (rebind receive
).
Maybe it would be enough to have even more obvious wording in the error message:
*** ERROR: unbound variable: b
evaluating procedure call (a b)
evaluating procedure call (receive (a b) ....)
Since error happens in the code that interpreting VM instruction, and at that time it's not trivial to find which is the "head" of the expression esp. after optimization, I guess it'd be a lot easier for the error handler to find and show relevant debug info than try to evaluate the head of S-expr.
Does the VM architecture make it tricky to look up bindings for each stack frame?
Yes. The stack frame won't necessarily correspond to the source code scopes. If I reimplement a debugger (I once had one, but it became obsolete after I rewrote VM) I need some debug info that precisely identify which variable is where, but I'll do it in the way that's not hinder performance, so looking up such info would be tricky.
I understand. If the evaluating procedure call
thing can be done easily, it would already be a big help.