masak / alma

ALgoloid with MAcros -- a language with Algol-family syntax where macros take center stage
Artistic License 2.0
137 stars 14 forks source link

Return isn't lexical enough in quasi quotes #63

Closed masak closed 8 years ago

masak commented 8 years ago

This has a nice error message:

$ perl6 bin/007 -e='return 42'
Attempt to return outside of any Routine
[...]

But look at this, that's internals leaking through:

$ perl6 bin/007 -e='macro m() { return quasi { return 42 } }; m()'
Variable '--RETURN-TO--' is not declared
[...]

Eew.

In fact, this is simply because the "Attempt..." error is a parse error, and that second return is inside of a macro... hm. We do have a similar throw in Runtime.pm, but maybe it's not triggered anymore.

But the real problem is this:

$ perl6 bin/007 -e='macro m() { return quasi { return 42 } }; sub foo() { say("A"); m(); say("B") }; foo()'
A

See? It returns from foo(), a routine it has no business returning from. Very unhygienic. Clearly it should be returning from the macro m, and we should be getting an error very much like this:

Routine already returned

In short, return should bind lexically to its surrounding routine, even if it's in a quasi. Just like variables do.

vendethiel commented 8 years ago

wait, what? why should it return from the macro? if I want to quasi a return, what's the issue?

masak commented 8 years ago

why should it return from the macro? if I want to quasi a return, what's the issue?

return lexically binds to its surrounding routine. Subs and macros are routines. Ifs and whiles and immediate blocks and BEGIN blocks and quasis are blocks, but they're not routines. As such, they are "transparent" to return.

If you want to return from a routine in your compiling context (the mainline), then we could support that, but that should probably be spelled COMPILING::return.

vendethiel commented 8 years ago

please no. That's mixing exactly the same level of things as my $a = 4; quasi { $a }, and it's only more confusing to everyone.

masak commented 8 years ago

please no. That's mixing exactly the same level of things as my $a = 4; quasi { $a }, and it's only more confusing to everyone.

I'll be honest and say that I don't think that bit is going to change unless a significantly more attractive and consistent counter-proposal materializes.

vendethiel commented 8 years ago

proposal: leave the separated levels separated. don't eval quasi-level code at the macro-level (or opposite)

masak commented 8 years ago

proposal: leave the separated levels separated. don't eval quasi-level code at the macro-level (or opposite)

There's only three possible outer contexts it makes sense for a quasi block to have:

  1. The one it's in, lexically
  2. The one it'll end up spliced in
  3. The built-ins

The first one is the current proposed semantics, for Perl 6 and for 007. Among the three, I do find it the most useful and least confusing one, in that it works like all other blocks/lookup in the language.

The second one is easier to implement, but means that un-hygiene is the default. I'm all for allowing un-hygiene, but I don't think it should be the default.

The third one I haven't considered, but I don't really see an advantage to it. It feels strictly less powerful than either of the other two.

I confess to not relating well to your phrase "don't eval quasi-level code at the macro-level". (To me it's just scoping as usual.) Maybe that means I misunderstood; if so, please feel free to clarify.

vendethiel commented 8 years ago

I don't think returncounts as "un-hygiene", FWIW, Hygiene is largely regarded as only being about name clashes. if you want to prevent returns from being inserted as unhygienic, do you also want to prevent throws?

masak commented 8 years ago

I think implicit in my points is that in Perl 6, return is lexical. (Or, more exactly, lexotic.)

In other words, the relation between return and its surrounding sub is not all that different to the relation between variable use and that variable's declaration. They're both predictable because they're static, dependent only on lexical program structure.

To answer your semi-hypothetical question, die semantics does not fit into this thinking, because the "declare" end of that is an in-general-unknowable catch clause up the CALLER chain. In other words, die sets up a dynamic communication with its catch where return sets up a lexical one with its sub.

masak commented 8 years ago

Putting it a third way, I consider this issue to be a special case of #47.