[e-lang] scoping rules of when-catch

David Hopwood david.nospam.hopwood at blueyonder.co.uk
Sun Jul 23 15:44:30 EDT 2006


Mark S. Miller wrote:
> David Hopwood wrote:
> 
>> # This means that the user defined __if and __while constructs can
>> # properly simulate the built-ins (except that the built-in 'while'
>> # can magically bind __break and __continue, though the user-defined
>> # __while cannot).
>>
>> What changes would be necessary to lambda-args to make exit constructs
>> like 'break' and 'continue', and similar constructs for user-defined
>> control abstractions, work correctly?
> 
> I think the answer must be "they can't". If they could, the whole
> rationale for user-defined control constructs
> <http://www.erights.org/data/irrelevance.html> would be violated.
> User-defined control constructs must be scope analyzable by the
> programmer when looking at a use occurrence without looking up or
> needing to know the defining occurrence.

'break' and 'continue' don't violate scope analyzability because each
'for' and 'while' loop *always* implicitly defines these names. So, when
you see a 'break' or 'continue', you can apply the scope analysis rules
as though explicit 'break' and 'continue' definitions had been added to
each looping control construct, like in the example you give:

> A while construct like
> 
>     __while (condExpr) fn __break, __continue { bodyExpr }
> 
> would work, since the defining occurrences of __break and __continue
> appear explicitly.

The same would be true of user-defined control constructs provided
that we can tell precisely which constructs should be analyzed in
this way.


Suppose we define a construct 'control' so that, for example,

    control myConstruct (condExpr) { bodyExpr }
==> __myConstruct (condExpr) fn __break, __continue { bodyExpr }

(As you mention below, this is not quite right as regards the scope
of __break, but that is fixable.)

Then, although 'for' and 'while' would still have to be built-in, their
expansions would become trivial:

    while (condExpr) { bodyExpr }
==> control __while (condExpr) { bodyExpr }

    for kPattern => vPattern in collExpr { bodyExpr }
==> control __for (kPattern, vPattern, collExpr) { bodyExpr }

(well, the latter would work if patterns were first-class, anyway).

I.e. the "magic" is restricted to the 'control' construct, whose purpose is
only to add definitions of 'break' and 'continue', and nothing else. To
me this approach would be less magical.

> With pragma.enable("lambda-args") turned on, this
> expands to
> 
>     __while.fn__control_1_2(fn{
>         [[condExpr], fn __break, __continue { bodyExpr }]
>     }).run__control()
> 
> In the mangled verb name sent to __while, the "1" is the arity of the
> parenthesized expression list following the __while. The "2" is the
> arity of the function representing the body of that clause.

<aside> This mangling is rather ugly. There must be a better way. </aside>

> The __while
> in the current E library does not currently respond to
> "fn__control_1_2", and I doubt we will extend it to do so. Instead,
> because of this issue, I expect the "while", "for", and "to" expansions
> to remain built in.
> 
> Note that the above doesn't quite succeed at simulating the semantics of
> the built-in while syntax. In the built-in while, __break is in scope
> for both the condExpr and bodyExpr. For both the built-in and the above
> example, __continue is in scope only for the bodyExpr.

This is easy to fix. Something like:

    control myConstruct (condExpr) { bodyExpr }
==> def __break; myConstruct (&__break, condExpr) fn __continue { bodyExpr }

which is then expanded using lambda-args. The expansion of while stays as
above.

-- 
David Hopwood <david.nospam.hopwood at blueyonder.co.uk>




More information about the e-lang mailing list