Re: TC39 bashing

2012-05-11 Thread Grant Husbands
Oops, obvious typo:

Grant Husbands wrote:
> In the case of at least some of these shims, it seems that adding A=>B
> to any weakmap and not undoing it later means than either B or W will

"any weakmap" should be "W".

G.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: TC39 bashing

2012-05-11 Thread Grant Husbands
Brandon Benvie wrote:
> Yeah I modified gozala's method a bit. The value isn't kept in valueOf,
> rather in a null proto object that allows different WeakMaps to not step on
> another one.

I could easily be misunderstanding things, so I'll be brief. Under the
standard WeakMap, if I have a WeakMap W, an Object A and an Object B
and I add A=>B to the WeakMap, the behaviour is that both W and A
being reachable (during GC) will make B reachable, but that neither of
them being reachable alone will make B reachable.

In the case of at least some of these shims, it seems that adding A=>B
to any weakmap and not undoing it later means than either B or W will
reachable for as long as A is, whether or not they are otherwise
reachable.

Regards,
Grant Husbands.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: value objects

2012-03-20 Thread Grant Husbands
David Herman wrote:
> There's a rough draft of the strawman here:
>
>    http://wiki.ecmascript.org/doku.php?id=strawman:value_objects
>
> Comments welcome!

Overall, I think it's a good idea. I have to admit that I did at first
get excited that custom value types and operator overloading might be
in, but I can cope.

This feature could also lead towards types that aid in SIMD
optimisation for graphics work, if such is problematic right now. Even
if they aren't part of this proposal, they might usefully guide some
detail.

Even though it's listed as a to-do, I wondered whether a discussion on
overflow might be fruitful. I have no great ideas, myself, but I think
that significant nimbers of people would vote for each of wrap-around,
saturation, error values and exceptions. I wonder whether there's any
easy way of supporting them all. Anyone have any interesting ideas? Of
course, implementation costs are an important aspect.

Regards,
Grant Husbands.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: lexical for-in/for-of loose end

2012-02-07 Thread Grant Husbands
Andreas Rossberg wrote:
>>> let a = [], b = [], c = [], d = []
>>> for (int i = 0, f = function(){ return function() { ++i } }; i < 10;
>>> d[i] = function() { return i }, ++i) {
>>>  a[i] = f;
>>>  b[i] = f();
>>>  c[i] = function(){ return i }
>>> }
> But note that the environment in b's closures is not the for-loop
> environment. Instead, it is a local environment, whose parent is the
> for-loop environment. To make that case work, it is not enough to be
> able to modify the [[Scope]] environment of closures -- in general,
> you'd need to swap out arbitrary parts of an environment chain.

Indeed. I specified that operation as a recursive, constructive
operation, in something like spec-lingo, in one of my emails, and
pointed out that it is likely to introduce an extra indirection in
most JS engines, for at least some scopes, due to its assumptions
about envRec; I noted (and Brendan agreed) that such could be a major
problem. To recap, it looked like this (this time writing it as JS):
function ReplaceEnvInEnv(E, C) {
  if (E==C) return new Env(E.outer, E.envRec.clone());
  else return new Env(ReplaceEnvInEnv(E.outer, C), E.envRec);
}
(You would pass it the [[Scope]] of a closure in E and the loop
iteration scope in C and it would give you a new [[Scope]] for that
closure.)

I'm hoping that someone knowledgeable about Chez Scheme's flat
closures will let us know about the similar detail of that and the
pitfalls.

> This is not merely a question of complexity, though. It's more
> fundamental. Environments are immutable mappings from names to
> locations -- that's a basic axiom of lexical scoping.

Well, lexical scoping is scoping in which names refer to (more or
less) the local lexical environment. That is still true under the
proposal. It might indeed be desirable for the mapping to be
immutable, but I don't think that's a given. The above recursive
design does not require direct alteration of mappings.

> Breaking it will have unforeseeable consequences.

I'd agree with a phrasing like "Breaking it may have unforeseen consequences".

> That may be vague, I agree, but I
> prefer not to find out concretely. :)  Subtle combinations of
> higher-orderness and state rarely let you down in terms of nasty
> surprises.

I agree that this proposal may run up against some of the core values
and idioms of javascript and may want to be rejected for that reason;
in fact, I would probably currently vote against it, if I were asked
to participate in a vote. However, I'll continue to try to make sure
we're all on the same page as regards the potential design details and
workarounds, and hope not to bother people too much.

Regards,
Grant.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: lexical for-in/for-of loose end

2012-02-07 Thread Grant Husbands
On 7 February 2012 13:32, Andreas Rossberg  wrote:
> What are the "closures that were created",

They are the closures that lie lexically within the loop's code,
outside of the init, (or, put differently, those that have the loop's
environment record in scope) and that were instantiated in the current
iteration.

> and how do you keep track of them?

In a linked list or array. Somewhere that sits with the loop state. In
desugaring terms, it could be expressed as an array, perhaps of weak
pointers, in the outer loop scope. I haven't got up to speed on Chez
Scheme's closures enough to answer this question for those.

> What should the following do?
> let a = [], b = [], c = [], d = []
> for (int i = 0, f = function(){ return function() { ++i } }; i < 10;
> d[i] = function() { return i }, ++i) {
>  a[i] = f;
>  b[i] = f();
>  c[i] = function(){ return i }
> }
> print(c[2]()); print(d[2]())
> a[4]()(); print(c[4]()); print(d[4]())
> b[7](); print(c[7]()); print(d[7]())

Here's what it does under the proposed scheme:
c[2]() -> 2
d[2]() -> 3
a[4]()() increments the i that is 10 to 11.
c[4]() -> 4
d[4]() -> 5
b[7]() increments the i that is now 11 to 12.
c[7]() -> 7
d[7]() -> 8
Basically, the closures lexically within the loop init always see the
latest version of i. Those lexically within the rest of the loop
always see the i that was available at the end of their iteration. The
iteration part of the loop is considered to be at the start. A related
gotcha is that d[9]() would return 12, if added to the end of that
sequence of calls. (I'm answering to the best of my ability, not
trying to defend anything.)

> And imagine the fun you can have with generators!

Indeed, you'd need to alter the [[ExecutionContext]] of suspended
generators whose [[Code]] lies within the loop (as well as altering
the [[Scope]]), which may be a bigger deal than just modifying
[[Scope]]s.

> Allow me to be blunt: this is literally raping the concepts of
> declarative environment and lexical closure. It is a hack, completely
> non-orthogonal,

I think that may be more than blunt; it is strongly emotive and also
vague enough that it can't really be answered. However, I and others
do share the concern that it may introduce too much complexity, and
then only really add support for a very rare usage.

> and I predict that the hidden statefulness it introduces to closure
> environments would be going to bite back in gore proportions.

It's a possibility, indeed. The variant that alters only the closures
lexically within the loop init has less chance of that, and could
potentially have restriction imposed, but all of these variants do
indeed introduce a way of (slightly) modifying the scope of a
particular group of closures after they have been created.

> Seriously, before we consider going there, I'd rather have a step on
> the break and stick to C-style for-semantics.

I think we wouldn't need to go that far; your generalization of Mark's
desugaring covers plenty of use cases and certainly the one of most
common loop/closure gotchas. To my understanding, that's the favoured
idea, so far, and we're just exploring this one to see where it might
lead.

Regards,
Grant Husbands.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: lexical for-in/for-of loose end

2012-02-06 Thread Grant Husbands
Brendan Eich wrote:
> I still do not think it's wise to specify in terms of such pointer-updating
> reference semantics, not for the body closures that want to capture loop
> control variables. But only if closures in the for-head capture loop
> variables? That would be Allen's "DWIM" (Do What I mean) semantics.

I think what you're saying here is that we would only ever need this
environment-copying trickery if there were closures in both the init
and in the rest, in which case I agree. Let-loops with closures only
in the init could then use the simplest semantics and let-loops with
closures only in the rest could use any of the desugarings. It's
starting to sound like a significant addition to the static semantics,
but I'll leave it to others.

Otherwise, maybe "Herby's init-swap", below, is what you're after? It
only alter closures in the init.

> Agreed, with caution about bending the body closure model around this
> prematurely. If we pull it off, probably the body closures can do the same
> "optimization" -- but it's not clear we can pull it off.

I think I'm not understanding something, here, as I'm still not sure
how the suggested semantics constitute even a quoted "optimization"
(maybe I'm not sure what it's an optimization of), or why we'd need to
bend both body closures and init closures in the same runtime, but
I'll carry on.

> Any preference for 0th over 1st iteration scope for closures in INIT binding
> initializer expressions?

If the init binding's closures are not going to touch every one of the
iterations, I believe they should touch none of them, for consistency
(I think that means "0th"). But I don't feel strongly about it, and it
does look like implementation detail might favour "1st".

[snipped implementation details]
> is not going to give TEST and NEXT the "DWIM" semantics. Sorry, I'm
> sure you get this, I'm just spelling it out to be sure everyone (including
> me) gets it.

I indeed agree; TEST and NEXT are essentially part of the body, since
they have always needed to reference the body's iteration variables
and are repeated alongside the loop body. And, to spell things out
further, it's the mechanism of "reenterblock" for these loops that
this thread is discussing, as I understand it.

> Why should they form closures that magically reference "current
> iteration scope" when called later?

Indeed, closures in TEST and NEXT must clearly be instantiated per
iteration and they lie naturally in the body, under all intuitive
desugarings, so they might as well be treated in the same manner as
the body.

> DWIM always falls to ambiguity. What did you mean? I dunno, just do it! :-P

Indeed, and individual and sometimes obtuse use cases can have more
influence than they perhaps should. (That's not a sly jab at anyone.)

Based on my reading of what you wrote, but without being able to point
at any one particular quote, I think there may still be a
misunderstanding of some kind, so I think we might benefit from me
spelling out a run-through under the versions of Herby's idea covered
so far. Note that I can't guarantee that this is a correct formulation
of Herby's idea, but I am fairly sure it is. Also note that each
formulation is entirely distinct. We'd never use both in the same
runtime.

In each case, the example code is as follows:
for (let i=0, inc=function(){++i};i<2;inc())
 setTimeout(function(){alert(i)},200);

Herby's formulation (and my second variant), which I'll call "Herby's
body-swap", would proceed as follows:
1. Scope with i and inc created for the loop.
2. Loop starts.
2a. The inc() isn't run, since this is the first time round the loop.
3. i<2, so we carry on.
4. The body closure gets created and points at the active i, which is 0.
5. The iteration ends and the next one starts.
5a. The body closure that was created gets cloned variables, with i==0.
5b. inc(), so i becomes 1.
6. i<2, so we carry on.
7. The body closure gets created and points at the active i, which is 1.
8. The iteration ends and the next one starts.
8a. The body closure that was created gets cloned variables, with i==1.
8b. inc(), so i becomes 2.
9. i<2 is false, so we're done.

At this point, we have two internal closures, with i==0 and i==1, and
the inc closure can see i==2, which is indeed the value i would have
after the loop was over, which seems intuitive.

The mechanism for cloning loop variables could be like any of Herby's
suggestions or the CopyDeclarativeEnvironment operation I suggested.
Note that that variant only needs one scope for the whole loop, though
the cloning operation creates its own.

My other formulation, which I'll call "Herby's init-swap", would
proceed as follows:
1. Scope with i and inc created for the loop.
2. Loop starts
2a. The loop's implicit internal let block starts and copies i and inc.
2b. The inc gets updated to point at the current iteration scope.
2c. The ++i isn't run, since this is the first time round the loop.
3. i<2, so we carry on.
4. The closure gets created 

Re: lexical for-in/for-of loose end

2012-02-06 Thread Grant Husbands
Brendan Eich wrote:
> [Grant Husbands wrote:]
>> 'Note' all closures (dynamically) created in (lexically) the loop
>> initializer.
>
> Only in the initializer? Why should closures formed there be dynamically
> scoped to the current iteration?

Because that directly serves the use cases that have
for-initialization-based closures modifying loop variables. None of
the simple desugarings do that, beyond perhaps the first iteration.

> Instead [this requires] a dynamic scope for closures in the initializer
[...]
> Dynamic scope is a warning sign, almost always a mistake.

Indeed, given the eval shape-changing problem you pointed out, this
cannot be properly resolved, in the first form of this proposal. The
second form might not require generalised dynamic scope, though; it
requires an operation that clones a scope with a single environment
record changed, though. More on that, later.

>> Or, here's one that copies the other way (and is probably cleaner):
>> 'Note' all closures (dynamically) created in (lexically,
>> post-desugaring) the loop body. Each time you end an iteration, update
>> all the loop variable activation record pointers to point at a new
>> clone of that activation record.
>
> This is a more complex spec than one that models each iteration having its
> own lexical scope. The spec needs only declarative environments, not hidden
> references and pointer updates.

I think there may be a misunderstanding, as the operation I'm talking
about can be given in spec language without talk of references and
pointer updates. I'll write it out at the end of this email.

> As an implementation technique, Chez Scheme's heap boxing and assignment
> conversion could be even better.

Indeed, and that introduction of a level of indirection for affected
variables is what Herby was effectively suggesting, if I'm
understanding you both correctly. I was trying to suggest something I
thought was more compatible with the current specification.

>  But this is all beyond the spec.

I don't think it is. What Herby's idea and these formulations present
is a way for let-based loops to have modifications in closures
captured in the for-head that alter the loop variables in a way that's
visible to the current loop iteration. As such, choosing whether or
not to use these formulations affects the spec.

I agree that it may indeed be too large a feature, given that
desugarings can cover the vast majority of use-cases well enough. I
just thought it worth following the logic through.

> Still trying to be sure you intended a unique and dynamic scope for the
> initializer (first part) of for(let;;).

In the first version, depending on the definition of "dynamic", yes.
In the second version, no, though instead closures inside the loop
body get a similarly 'dynamic' scope.

Here's a longer, still informal version of the second.

Given a loop of this form:
for (let i = 0, inc = function(){i++}; ihttps://mail.mozilla.org/listinfo/es-discuss


Re: lexical for-in/for-of loose end

2012-02-05 Thread Grant Husbands
Herby Vojčík wrote:
> I meant all that copying there and back and having two variables with the
> same name in two scopes and handling all combinations when to access which
> one. I wanted to take this away.

Yes, at least my desugaring was indeed overcomplicated. Brendan's and
Mark's desugarings aren't that complicated, though.

>> Your proposal depends on being able to reassign variable pointers, but
>> they don't necessarily exist.
>
> Well, references are all over the spec (or were in times of ES5).

What I was calling activation records, the spec calls environment
records and it does not, by my reading, imply that variables within
them are reference-like in nature (read clause 10.2). However, we
don't need to argue this point.

>> Or, here's one that copies the other way (and is probably cleaner):
>> 'Note' all closures (dynamically) created in (lexically,
>> post-desugaring) the loop body. Each time you end an iteration, update
>> all the loop variable activation record pointers to point at a new
>> clone of that activation record.
>
> If I understood correctly, this is what I proposed. Or maybe it only looks
> like it?

It has the same behaviour, but without needing variable pointers; that
was the idea. I now propose it to the list as a variant of your idea
that I think some may prefer. I'm merely trying to make sure your idea
gets the attention it deserves.

To be completely acceptable, the mechanics would need fleshing out, of course.

Regards,
Grant.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: lexical for-in/for-of loose end

2012-02-04 Thread Grant Husbands
Herby Vojčík wrote:
> It looks to me that all those schemes and desugaring are very complicated

The full problem is complicated, so that's to be expected.

> What is bad with scenario of reusing the same variable and isolating it as
> local only for the async closures?

Your proposal depends on being able to reassign variable pointers, but
they don't necessarily exist. Though I haven't written a JS engine, I
believe they are allowed to have variables directly in an activation
record (or environment instance) without any (pointer) indirection, so
they'd have no mechanism for performing the operation you describe.

However, though I haven't read it, I believe that the spec talks a
great deal about these activation records and environments, so
specifying a mechanism involving those might give you more chance of
finding common ground.

For what you're talking about, I think this might be an equivalent
proposal that's more spec-friendly:
'Note' all closures (dynamically) created in (lexically) the loop
initializer. Each time you start an iteration, update all the loop
variable activation record pointers within those to point at the
current iteration's activation record (which should, with care, have
the same shape).

Or, here's one that copies the other way (and is probably cleaner):
'Note' all closures (dynamically) created in (lexically,
post-desugaring) the loop body. Each time you end an iteration, update
all the loop variable activation record pointers to point at a new
clone of that activation record.

In each case, you require a list of not-necessarily-predictable size
to note the closures in. That's not a big problem; it's just something
you need to be aware of.

Regards,
Grant.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: lexical for-in/for-of loose end

2012-02-04 Thread Grant Husbands
Brendan Eich wrote:
> I agree we want to capture the first-iteration bindings in any closures in
> those declarators' initializers.
>
> This requires unrolling the loop once. Let's see how the desugaring from:
[snip]

For what it's worth, I agree with Mark's (2008) and Brendan's
desugarings and hereby withdraw my own, as the value-copying covers
barely any more use cases. Without some extensive feature like
let-aliasing, as Herby suggested, those solutions as good as we're
going to get, though I could have missed some of the discussion so
far.

By the way, if apparent code duplication in Brendan's desugaring is an
issue, a small change will fix that, with little cost, like so:
$loopEnd: {
  let $initdone = false;
  const $loop = { |d1, ... dN|
if (!$initdone) {
  $initdone = true;
  d1 = e1, ... dN = eN;
}
if (!cond) break $loopEnd;
body;
update;
$loop(d1, ... dN);
  }
  $loop()
}

As for modifications done by the for-head's closures, I have no strong
opinions. In both proposed desugarings, those modifications would be
invisible to the loop body fairly quickly. And in all proposals that
don't involve some kind of extensive variable aliasing, the for-head's
closures cannot observe values set in the loop body (beyond the first
iteration).

However, I hope I don't delay consensus by raising the possibility of
another desugaring using consts:

$loopEnd: {
  const d1 = e1, ... dN = eN;
  const $loop = { |d1, ... dN|
if (!cond) break $loopEnd;
body;
update;
$loop(d1, ... dN);
  }
  $loop(d1, ... dN);
}

That way, the for-head's closures can't easily have hidden unexpected
effects, though they'll still observe incorrect iterated values, and
it's less of a sledgehammer than disallowing capture altogether.

It's late, so I apologise if I've missed something really obvious or
typed garbage.

Regards,
Grant.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: January 19 meeting notes

2012-01-20 Thread Grant Husbands
Jon Zeppieri wrote:
> Is there a version of this desugaring that deals with recursive
> bindings in the initializer expression of the loop?

How about something like this?
(given for (let  = ; ; ) {  } )

{
  let  = ;
  while(true) {
if (!) { break breakTarget; }
let  = ;
{
  // There might be a better way to copy values to/from shadowed variables
  // (using temporaries seems a bit weak)
  let  = ;
  continueTarget: {  }
   = ;
}
 = ;
;
  }
}

That way, all of the variable references in initExpr, testExpr and
updateExpr refer to a singular copy and all of the variable references
in body refer to the iteration-scoped ones.

So, looking at your example:
> for (let [i, inc] = [0, function() {i++;}]; i < n; inc()) ...

I think it now has the desired behaviour. However, people calling inc
from inside the body will still be surprised. I think solving that
probably requires something more advanced than a desugaring, as it
means the loop variables captured by that function (or, alternatively,
ones captured inside the body) need to point at different variables at
different times.

There's also an abstraction leakage if one breaks in the body, in that
the inner  doesn't get copied to the outer one. All in all,
not a great desugaring, but I thought it might be worth offering.

Maybe disallowing capture in the for (let ...;...;...) head would be easier.

Regards,
Grant Husbands.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Better Native XML Support

2012-01-17 Thread Grant Husbands
Russell Leggett wrote:
> If you desperately need it, you should be able to make a library for it, and
> then if you need the extra syntax, add an extra compile step

I was simply making sure everyone was on the same page as regards e4x
and was making suggestions to try to bridge the gap. I don't need it
myself, though I imagine the "you" there wasn't necessarily aimed at
me.

> I'm not saying its an insignificant effort, but it seems fairly
> straightforward. The standardized grammar for it is defined as an extension
> to Ecmascript after all.

Though source to source processors are a source of significant
friction (complicating build and debug), this would indeed be
something for the community of e4x supporters to consider. Hopefully,
the right people will see this thread.

I think that assignment into quasis may yet be useful, but perhaps it
doesn't belong in this thread.

Regards,
Grant Husbands.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Block Lambdas: break and continue

2012-01-17 Thread Grant Husbands
Allen Wirfs-Brock wrote:
> do: arr.alternate ({|o| if (...) continue; if (...) break; ...}, {|o| if
> (...) continue; ...});
>
> I don't see how this can support the most likely intended semantics

I think others might have better answers, but it seems that the
meaning of 'break' is to stop the whole statement, and the meaning of
'continue' is to skip the inner block and hence return to
arr.alternate. I'm sorry for my woolly language, but it seems
relatively equivalent to a for loop, in which 'break' stops the whole
statement and 'continue' skips the inner block and hence returns to
the looping code.

Perhaps what I'm saying is that I think "do:" is a label for the whole
callexpression, covering all lambda-block parameters. As far as the
specification goes, a continue that 'hits' the block lambda may well
be best described as a local return.

Or I might be misreading.

Regards,
Grant Husbands.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Better Native XML Support

2012-01-17 Thread Grant Husbands
David Bruant wrote:
> Have a look at quasis [1]. It provides what I'd consider to be a more
> generic and safer solution to E4X.

E4X is more than just data production, though. It added a number of
accessors/syntax for handling XML elements, many of which can be the
LHS of an assignment:
expr..ident // descendant selection
expr.@ident // attribute selection
expr.* // All-children selection
expr.(filter) // Filtering a set, with an implicit 'with'
@ident // At least within a filter, attribute selection
expr.var::ident // Using the namespace in var, descendant selection

In combination, they provide some concise ways of manipulating
document-free XML nodes, though with large number of downsides that
probably aren't worth covering in detail, here.

It might be worth considering bringing some of those constructs back
in a more generic and future-proof fashion in future versions of
ECMAScript. Or it might instead be worth considering allowing quasis
to be the LHS of an assignment, which would be useful and could then
cover more e4x use cases.

(I've removed es5-discuss from the recipients, since this is no longer
relevant to that)

Regards,
Grant Husbands.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Block Lambdas: break and continue

2012-01-16 Thread Grant Husbands
Brendan Eich wrote:
> 2. Variation on empty label: support "do" as a reserved-identifier label
>
>   do: arr.forEach {|o|
>     if (...) break;
>     ...
>   }

This seems like a sound way of doing it, indeed (I omitted your first
one because I prefer this one). It avoids the more egregious syntax
conflicts and is indicative of being interesting to break/continue.
Combined with the break-with and continue-with statements, elsewhere
in this thread, it makes block lambdas better than anonymous functions
currently are in nearly all cases, along with making it easier to
replace loops with callback-based iteration.

> To complete the Smalltalk homage we would want this in expressions, and
> we'd also want do: to take a block-lambda directly, in addition to a
> CallWithBlockArguments.

Would it call that block-lambda with no arguments?

> This variation is future-hostile to leading-colon as statement- or
> expression-starting special forms (see  /doku.php?id=strawman:return_to_label>). I think that this is
> acceptable but I could be missing something.

I think I'm misreading, but I'm not seeing how "do:" and "return :"
conflict. If break-with and continue-with get specced, they would
cover the same use case, anyway. I do agree that if ":" could start an
expression and "do" could be used without braces, there would be a
conflict; maybe there could be significant whitespace in that
situation. I'm sure people more qualified than myself will cover this,
though.

I don't know how the process works, but I'd be happy to assist in the
creation of additional strawmen to cover these (potentially later)
additions to block lambdas and other blocks, if consensus is reached.
I don't want to jump the gun, though.

Oh, and I do agree that credit goes to Axel for the proposal.

Thanks,
Grant.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Block Lambdas: break and continue

2012-01-15 Thread Grant Husbands
Brendan Eich wrote:
> I don't see how your proposal can work without exceptions. You write that
> it is syntactic sugar. Ok, what is the desugaring? How does
>
> for arr.ForEach { |o|
>   if (...) break;
> }
>
> translate into JS without a throw that the implementation of arr.forEach,
> which is not modfiied by this for-prefixed invocation, can catch?

The above would desugar to:
label1: arr.ForEach { |o|
  if (...) break label1;
}

If it had continue instead of break, it would desugar to:
arr.ForEach { |o|
  label2: {
if (...) break label2;
  }
}

It wouldn't need to be described as a desugaring in a strawman, given
the similarity to typical break/continue handling, but I think that
makes the meaning clear.

Regards,
Grant Husbands.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Block Lambdas: break and continue

2012-01-15 Thread Grant Husbands
Herby Vojčík wrote:
> your 'for call {|| ...}' is great and simple solution for (unlabeled) break,
> but it is not so for continue.

To clarify, it matches what continue currently does for other loops,
which is what I was aiming for.

However, I do agree that early completion with a value is desirable
and that continue could easily be adapted to accept a completion value
for the block lambda. I didn't mean to exclude the possibility;
rather, I just hadn't passed comment on it.

Do note that if it's added into my proposal as it stands, we only gain
that functionality on lambda block usage that's labelled as loop-like.
I don't know whether you find that acceptable, but it might be the
only way that it can be widely accepted, due to TCP.

Regards,
Grant Husbands.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Block Lambdas: break and continue

2012-01-15 Thread Grant Husbands
Brendan Eich wrote:
> More when I reply to Axel in a bit.

I think there may have been a misunderstanding. My proposed solution
amounts to syntactic sugar over the existing strawman and makes
break/continue work intuitively with loopy block lambdas, and your
reply to Axel appears to be against an exception-based version, but
you seem to have (implicitly) tied them together.

> Of course we want to uphold TCP, which constrains the design. What works
> here must work in a regular block statement as body of such a loopish
> structure.

Well, the LCP (Loop Correspondence Principle :) is maintained. So, you
can change your loop construct from:
for (var i=0; ihttps://mail.mozilla.org/listinfo/es-discuss


Re: Block Lambdas: break and continue

2012-01-14 Thread Grant Husbands
Brendan Eich wrote:
> > Exception handling is seldom used in the large except to void the
> > exception.
>
> And then only near or at a top-level event loop.
>
> Exception handling is the issue here, because of the proposal to add
> reifed break and continue as thrown exceptions. How exception
> handling is practiced (usually not) is highly relevant.

I agree that exceptions might not be the way to handle it. I've seen
it noted that something like these would work under the existing
proposal:

forEach(arr) { |a|
  skip: {
// ...
if (...) break skip; // Equivalent to continue
  }
};

end: forEach(arr) { |s|
  // ...
  if (...) break end; // Equivalent to break
};

The mechanism by which they work may give a more agreeable path for
implementation of the new kind of end/break, perhaps along with a
keyword near the forEach to enable the behaviour. It would also mean
that break/continue could still be matched with their jump-sites at
compile time. There'd be the caveat that the iterating function would
have no control over that flow, but that is already the case for
continue/break/return under the existing proposal.

To try to be clear, I'm implying a syntax akin to this could give the
desired break/continue functionality for lambda-block-based loops, and
could essentially desugar to the above:
for forEach(arr) { |a|
  // ...
  if (...) continue;
  if (...) break;
};

It would probably need alteration to not conflict with other recent syntax.

Regards,
Grant Husbands.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Block Lambdas: break and continue

2012-01-14 Thread Grant Husbands
I should have been clearer in my original message; I'll avoid
mentioning Ruby directly, again, as it misdirects conversation.

Though I have no strong opinion on block-lambdas in javascript, I will
try to restate my original position, for clarity:
Block lambdas, as currently described in the proposal and in the
community, have 'forEach' and similar as driving examples; I believe
that a typical programmer would expect break or continue to directly
affect that loop, and that that behaviour may be desirable.

Brendan Eich wrote:
> "Intuitive" depends on intuition, which is not well-defined.

True, but I do believe in intuition without the bias of a source
language. I understand that intuition can vary, so I might be aiming
for 'average practitioner's intuition' or such.

> Do you mean a Rubyist might expect different behavior for break?

I believe that the typical programmer, given the briefest exposure to
block lambdas, would believe that 'continue' would behave the same way
for a block-lambda-based loop as it does for any other loop.

> Wait, why do you think break and continue without label operands
> do anything other than break from the nearest enclosing loop

What I meant was that, in the typical examples, 'forEach' is the
nearest enclosing loop, and continue and break apparently bypass it.

> The Array.prototype.forEach method's internal implementation is
> its business, and a break instead of the return would be a static
> error in this example. It would not be a dynamic throw-like
> construct that is caught by forEach's implementation.

Indeed, the way break would need to work could be a show-stopper for
my proposed alteration, but I was trying to avoid implementation
detail. My intent was to raise the divergence from (in my opinion)
intuitive behaviour in the case of block-lambda-based loops.

Regards,
Grant Husbands.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Block Lambdas: break and continue

2012-01-13 Thread Grant Husbands
Block lambdas have been a hot topic, recently, but there's a point of
significant divergence between Ruby (which appears to be the inspiration)
and the proposed solution, in the handling of continue (called 'next', in
Ruby) and 'break'.

To whit: In Ruby, 'next' will end the current run (iteration) of the block,
and 'break' will (somehow) terminate the method lexically connected with
the block. It can be claimed that this is more intuitive than the current
proposal, which aims to make 'break' and 'continue' propagate through block
lambdas in the same way 'return' would.

Ruby does also support syntactic loops and the same keywords therein and so
directly violates Tennent's Correspondence Principle, even though such has
been touted as a core reason for the construct. Instead, I believe it
reasonable to invoke intuition in this matter. It is intuitive for 'return'
to return a value from the lexically enclosing method and it is intuitive
for 'continue' to commence the next iteration of the current loop, however
that loop is constructed.

Note that the label-based break/continue could still have the desired
effect, if the proposal was updated to be more like Ruby's blocks.

I don't have a strong opinion on the subject, but I hadn't noticed the
above being discussed, elsewhere, and thought it worth raising. If there is
a better place for me to raise this, please let me know where and accept my
apologies.

Regards,
Grant Husbands.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss