Peter van der Zee | 10 Feb 11:27
Picon
Favicon
Gravatar

Fallback

There's currently no way of introducing anything new into the language
that breaks syntax. I think that point has been made very clearly with
harmony/es6. Can we introduce a way to make these transitions easier
in the future?

CSS has a very simple way of gracefully ignore rules it doesn't know.
In CSS you can specify rules and features and whatever the engine
doesn't understand, it will ignore gracefully and continue. While this
obviously won't work out of the box for js. But I think we can work
around it. In CSS this is scoped to individual rules. In js there's no
notion of rules (and "lines" won't work either) but you could talk
about functions or modules (or blocks?) in the same way. I think
modules are a bit too big scoped for this but I'd like to discuss the
generic idea first. We can always bikeshed over the syntax later. I'll
work with function-like syntax for now.

Say a browser wanted to support a new keyword. Right now, that's
impossible to even experiment with unless you write an entire engine
in js and have a duplicate source code for fallback. You simply can't
do something like

x ||= y;

without breaking the code permanently and without exception. We can
only add stuff that fits perfectly within the existing grammar.
There's also no way for a vendor to implement this as an experiment
because it will still break in older versions of the browser or other
vendors. So what if we could do something like this?

function foo(x,y){
(Continue reading)

Nebojša Ćirić | 9 Feb 00:58
Picon
Favicon

I18n clarification needed for 8.4.5 [[LookupSupportedLocalesOf]]

I am not sure what result we expect from LookupSupportedLocalesOf.


Thy way I read the spec is that if user passes requestedLocales = ['sr-Latn-RS'] and supportedLocales = ['sr'] then we would return ['sr-Latn-RS'].

I feel it would be more useful to return the actual supported locale, in this case ['sr'].

Implementation wise it's trivial to get either one of those.

--
Nebojša Ćirić
_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss
Mark S. Miller | 8 Feb 22:47
Picon
Favicon

Fwd: Paper on Proxies

Enjoy!

---------- Forwarded message ----------
From: Tom Van Cutsem <tvcutsem-t4LwSHXjkAOzQB+pC5nmwQ@public.gmane.org>
Date: Wed, Feb 8, 2012 at 1:12 PM
Subject: Paper on Proxies
To: TC39 <e-tc39 <at> ecma-international.org>


Hi,

I recently finished a paper (co-authored with MarkM) that spells out the details of the design of (direct) proxies and the reflection API. [...]

I've also written up the story behind the paper here:
http://soft.vub.ac.be/~tvcutsem/invokedynamic/esharmony_reflect

[...] it's published as a techreport [...], so feel free to circulate.

Cheers,
Tom



--
    Cheers,
    --MarkM
Attachment (vub-soft-tr-12-03.pdf): application/pdf, 332 KiB
_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss
Claus Reinke | 8 Feb 22:19

modules: import hiding, and usage patterns

Just saw this wiki update (*)

    http://wiki.ecmascript.org/doku.php?id=harmony:modules&do=diff&1328732818

and this sentence:

    If there is a conflict between the names from two distinct imports,
    and exactly one of the imports uses the ''*'' form, then the other
    import takes precedence.

I have two issues with this:

- implicit override instead of ambiguity warning/error
    (add an explicit import, and change semantics of implicit
    imports elsewhere in the current module, without a type
    system to catch the change)

- no way to filter items from the "*" form
    (can't resolve ambiguities explicitly)

I would prefer a way to resolve such ambiguities explicitly
by selectively hiding imports (import * hiding {x,y} from M),
with warnings/errors for unresolved ambiguities.

If there is going to be an implicit "import *" from a standard
prelude, it would also be good to have a way to turn the
implicit import into an explicit import (with selective hiding).

Great to see updates to the modules proposal - could you
please have a look at the module usage patterns outlined in

    supporting ES upgrading with a programming pattern repo?
    https://mail.mozilla.org/pipermail/es-discuss/2011-November/018240.html

It would be nice to see how these patterns will be handled
by ES6 modules (I hope the answer isn't always "use loaders",
but JS coders seem to have grown used to dynamic module
usage patterns which don't seem covered by the static aspects
of ES6 modules).

Finally, about the wiki: the list of old page revisions for each
proposal links to page revisions, not to diffs - am I missing
something, or could the wiki be configured to add diff links
(to previous revision)? Also, the RSS feed still has escaped
URLs, so the links do not lead to the intended page (*).

Claus

(*) the wiki RSS feed url escape problems still persist:
    https://mail.mozilla.org/pipermail/es-discuss/2011-April/013927.html
Herby Vojčík | 7 Feb 19:56
Picon
Gravatar

Explicit local copies (was: Re: lexical for-in/for-of loose end)


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.

Oww, that's a problem. Copies are hard here... refs can do it, but no 
one likes them.

> I am fine with either. So far I have favoured
> fresh-variables-per-iteration, but the current discussion has raised
> some doubts in the back of my mind.

This whole discussion leads me to completely different opinion: what 
about to embrace "explicit is better than implicit" for this case, and 
allow let/const without initializer to create local copy of an outer 
variable?

Then, if you need to capture a value, you write it down (I know this 
appeared to avoid capturing by hand in (function (i) { ... })(i), but 
reusing normal blocks to do it may work, wouldn't it?

It disallows some of the ninjutsu (init-closures will work with 
different i than localized closures), but it will be clearly visible:

   let a = [], b = [], c = [], d = [], e = []
   for (int i = 0, f = function(){ return function() { ++i } }; i<  10;
     d[i] = function() { return i }, ++i) {
     a[i] = f; // this
     b[i] = f(); // and this
     c[i] = function(){ return i } // and this work with loop-level i
     {
        let i;
        e[i] = function () { return i; } // this has local i
     }
   }

> /Andreas

There can be even shorter syntax, like
        e[i] = function () let i { return i; } // this has local i
or
        e[i] = function () { let i; return i; } // this has local i
whoch can avoid need of {} block, but it must be thought of if it is 
possible consistently (the former should, the latter may be questionable).

Herby
Norbert Lindenberg | 7 Feb 19:27
Favicon

Globalization API: Prototype objects

The current specification of the ECMAScript Globalization API requires the prototype objects for the
LocaleList, Collator, NumberFormat, and DateTimeFormat constructors to be objects constructed by
these constructors themselves. This is following a pattern established in the ECMAScript Language
Specification, which requires the Date prototype object to be a Date object, the RegExp prototype object
to be a RegExp object, etc.

At the November TC 39 meeting, there were some comments that this is not the recommended pattern anymore.
Instead, prototype objects should be minimal objects with just those properties (mostly methods) that
all constructed objects should inherit.

Which way should the Globalization API go?

Regards,
Norbert
Allen Wirfs-Brock | 7 Feb 03:51
Favicon
Gravatar

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


On Feb 6, 2012, at 5:32 PM, Brendan Eich wrote:

> Grant Husbands wrote:
>> Now, there are some advantages and disadvantages:
> 
> Thanks for expanding on your and Herby's proposals, it helps. A disadvantage on its face of "Herby's
init-swap" is that variables are copied from iteration scope to iteration scope, *and* all contained
closures need their [[Scope]] adjusted every iteration.
> 
> For the code you evaluate "Herby's body-swap" against, the "flat closure" (Chez Scheme "display
closure") formation is indeed good optimization. The closure passed to setTimeout post-dominates the
only live (from its point of view) assignments to i, so copying i's value into the closure allows very fast
access and no scope entrainment at all.
> 
> A harder case would mutate upvars after the closure is evaluated, so that it must capture references not
values. In any case, the scope would need to be cloned on each iteration where closures formed, and those
closures' [[Scope]] internal properties updated.
> 
> Allen should comment on whether this attempt to square the circle (kidding, mostly) might fly in the spec.
Implementors while secondary should weigh in too.

My sense is that we could make these schemes works in spec. space.  Either by allowing bindings that have
References as values or by adding new mechanisms such environment cloning.  

It actually sounds fun and perhaps even the "right thing" to do.  However,  I have some doubts concerning
whether the added work and spec. complexity is really justified by the benefit.  Maybe, but there are lots
seemingly more important things to work on.

With "body-swap" it concerns me a bit that is an arbitrary and variable number of closures may need to be
updated each iteration (consider a body containing a while loop that spits out closures that capture init bindings.)

For both, I need to think about whether it may be possible (and the impact) for a closure activation
(containing a generator?) to span a iteration boundary.

Allen
Jason Orendorff | 6 Feb 20:09
Picon

What should Map iteration do?

On Thu, Feb 2, 2012 at 1:35 PM, Allen Wirfs-Brock <allen <at> wirfs-brock.com> wrote:
>  for (v of arr)  // each element of an Array
>  for (v of set)  // each value in a Set
>  for (k of map)  // each key in a Map, following Python
>
> Smalltalk defaults maps to the value and Ruby to the key/value pair.  Java
> seems to have no default, you have to explicitly select keys, values or
> items.

Trying to revive this thread...

In C#, a Dictionary<K, V> is an ICollection<KeyValuePair<K, V>>. So,
items by default.

Note also that in Ruby it's not as simple as "defaulting to" key/value
pairs. Actually if you write code like
    obj.each { |v| puts v }
which is what you'd write for walking an Array, that doesn't work with
a Hash. Array#each expects a block with one argument, but Hash#each
expects a block with two arguments. (If you call Hash#each without any
block argument, you do get an enumerator that yields pairs, but that
is not the usual thing to do in Ruby. That is, typical generic
collection algorithms in Ruby do not reach Hashes.)

> The rationale for Smalltalk, is that most generic algorithms that want
> iterate over arbietrary collations are interested in values.  After all,
> some collections don't have keys.

Until Python 2.2, iterating over a dictionary was an error. Python
2.1.3 was the last version where you had to specify keys/values/items,
and in that version of the Python standard library, the numbers are
like this:

    for.* in.*keys():    114 hits, 86 distinct
    for.* in.*items():   110 hits, 85 distinct
    for.* in.*values():   19 hits, 16 distinct

This fits with my experience. When each value is a serious object from
which you can easily get or compute the key, values() is exactly what
you want. Otherwise values() is unhelpful, usually.

I want to do the same experiment on a large body of Java code. Since
Java does not have a default, the results should show what's most
useful (in Java) in practice. I can use Apache commons code, for
example. I'll try to find time this week.

I think the "generic algorithms" perspective should argue for items()
iteration being the default. At issue is what a function like map or
filter should do with a Map; it seems most general to expose all the
information in the Map by default. However: passing a Map to a generic
algorithm is only one use case for Map iteration, and not the most
common in my experience.

-j
_______________________________________________
es-discuss mailing list
es-discuss <at> mozilla.org
https://mail.mozilla.org/listinfo/es-discuss
Brendan Eich | 6 Feb 16:37
Picon
Favicon

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

Andreas Rossberg wrote:
> On 4 February 2012 18:49, Brendan Eich<brendan@...>  wrote:
> In other words, why isn't the following good enough?
>
> {
>   let d1 = e1, ..., dN = eN;
>   const $loop = {|d1, ..., dN|
>     if (cond) {
>       body
>       update;
>       $loop(d1, ..., dN);
>     }
>   }
>   $loop(d1, ..., dN);
> }

This is the "0th iteration scope" idea. It's good enough if (a) we want 
skip2 (see last post) affecting no iteration's loop variables, and (b) 
we can take the extra scope cost-hit.

> FWIW, this is simply the generalization of Mark's desugaring so that
> it works with destructuring, multiple bindings, and recursive
> bindings. Plus, it removes the redundant second lambda in his version.

It's fine if we like (a) on usability grounds, and (b) is true for all 
implementors and wtf-benchmarketing kooks.

I argued vigorously for 1st-iteration rather than 0th-iteration scope 
but that was to say "no" to (b). I'm actually not sure what skip2-coding 
authors will want -- probably an error as Allen suggests. But let's say 
yes to (a) -- I can live with (b) absent further evidence.

The issue remains (a). Allen's best shot is the skip2 scenario (advance 
in his post). What's the right outcome for users who write such code?

/be
Allen Wirfs-Brock | 4 Feb 23:19
Favicon
Gravatar

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


On Feb 4, 2012, at 12:55 PM, Brendan Eich wrote:

> Allen Wirfs-Brock wrote:
>> On Feb 4, 2012, at 9:49 AM, Brendan Eich wrote:
>>> I agree we want to capture the first-iteration bindings in any closures in those declarators' initializers.
>> 
>> It isn't clear to me why capture first-iteration is abstractly any better than "capture a hidden second
x".  In both cases, in most iterations of the loop, evaluation of any such captures is going to reference the
"wrong" binding.
> 
> The argument is as follows:
> 
>  for (let i = 0, a = some.array, n = a.length; i < n; i++) { ... }
> 
> here we definitely want the a in a.length (n's initializer) to be scoped by the head let -- to be the a
declared by the second declarator.
> 
> Now consider a bit of eta conversion:
> 
>  for (let i = 0, a = some.array, n = (function(){return a})().length; i < n; i++) { ... }
> 
> It would be quite wrong for the a captured by the anonymous function expression to be other than the a
binding declared and initialized immediately to the left.
Yes, I support the general principal that that initializers of bindings capture to the left.  But the
problem here is that conceptually the let is defining multiple bindings (one per iteration).  I don't
think many people are actually going to understanding the details of the proposed semantics and their
implications.  Since most uses won't involve closure capture, any of the proposed semantics that have per
iteration bindings with forward value propagation are just going to do the "right thing".  That is good. 
However, I doubt that someone who actually codes a function in a for(let;;) initializer is going to be
thinking, "of course, this only captures the first iteration bindings".  

> It would be bad for the eta conversion to break equivalence (use a block-lambda instead of a function
expression for full TCP).

With the TDZ alternative I proposed, there  would still be equivalence for:
     for(let x=x;;)...;
and 
     for(let x={|| x}();;)...;

Both throw for accessing an initialized variable.

But you're right that equivalence is lost for 
     for(let x=n, y=x;;)...;
and 
     for(let x=n, y={|| x}();;)...;

Whether this is better or worse than the "wrong capture" issue complete depends upon the actual programmer intent.

> 
> 
>> From a user perspective, the main advantage I see for capture first iteration is that it has a slightly
smaller window of wrongness.  The captures evaluated in the first iteration will reference the
correction binding, while latter iterations reference the wrong binding.
> Users expect and even (now that they know, and Dart raises the ante) demand that each iteration gets fresh
let bindings. Any who do capture an initial binding in a closure must know, or will learn, that it's just the
first one, which fits the model.

For the latter, I strongly suspect that they won't know and will be WTF surprised when they encounter it.  The
saving grace is that this will probably be very rare, although its possible that the introduction of block
lambdas might somewhat change that.  Just don't know...

> If this were really a footgun (I don't believe it is without actual evidence from the field) we could try to
ban closures capturing the initial bindings. That ad-hoc restriction would be quite a wart. It doesn't
seem warranted.
> 
My TDZ solution is such a restriction.  But I don't see how it is any more ad hoc than any of the other changes we
are talking about here in order to give for(;;) per iteration bindings.  Its wartiness  actually seems
small and is restricted  to a situation where the programmer probably is actually expecting C=style per
loop rather than per iteration binding. 

>> From an implementation perspective, it is probably a bit simpler to not have the extra hidden binding for capture.
> 
> I don't think so. The unrolling I showed was to use a tail-recursive block-lambda helper. But real
implementations will do closure analysis and optimization (flat AKA display closures, e.g.) and use
branch instructions for loops, jumps for breaks, etc. Having the first binding rib open a bit earlier than
subsequent ribs is (I think) a small or zero-cost issue.

My comment wasn't about the bind to first unrolling.  It was about the "extra hidden binding" alternative in
the first list of alternatives and is probably also applicable to by TDZ alternative.

> 
>> I really don't like the first iteration is different semantics
> 
> Different how?

Different from subsequent iterations...

Take Jason's example

   for (let i = 0; i < n; ) {
       setTimeout(...closure using i...);
       if (shouldAdvance())
           i++;
   }

If somebody decided to abstract the increment:

   for (let i = 0; advance={|| i++}; i < n; ) {
       setTimeout(...closure using i...);
       if (shouldAdvance())
         advance();
   }

advance does what is intended if called on the first iteration, but not on subsequent one iterations. I'd
soon get an error when I ran this than having it get stuck in a loop.

> Making the first iteration's binding initialization capture guaranteed errors would be different
semantics. Capturing the first iteration's bindings from closures in their initializers is not
"different" any more than having initializers is "different". The initialization part of the for loop is
already special. It's not like the update part.
> 
>> and think we should think about the above alternative.
> 
> Eta equivalence matters. Given that we want n = a.length to use the a declared to the left in the same
for-head declaration, I don't see how we can make closures in a right-ward initializer capture some outer binding.
> 
> Capturing an error-only binding would need evidence of the footgun not being useful for shooting other
things. We don't have such evidence, not by a long shot.

Well, we don't have a lot of evidence for any of this discussion.  Does any C-syntax language currently
implement for(;;) in the manner that is being proposed?
> 
>> However, such closure capture is very rare (could use of block lambda based patterns change that??)
> 
> I don't think so -- equivalences are stronger, not weaker or different, with block-lambdas vs.
functions, due to TCP.
That was the point I have had in mind.  While function expressions in for(;;) initializers are now rare, that
might change with the use of block-lambdas
> 
>> so it may come down to judgements about implementation costs.  Is capture first going to be significantly
easier to implement than my alternative scoping? The answer is obvious to me.
> 
> Did you mean "isn't"?
yes
> 
>> In either case an implementation is like to special case loops with closure capture in their initializers.
> 
> Varying a sketch Jason posted to the SpiderMonkey internals list:
> 
>    for (let V = INIT; TEST; UPD)  STMT
> 
> compiles to
> 
>        enterblock <V>
>        INIT
>        goto L2
>    L1: STMT
>        reenterblock
>        UPD
>    L2: TEST
>        iftrue L1
>        leaveblock
> 
> This is very close to how SpiderMonkey compiles for(let;;) already -- the only new instruction is
reenterblock, which exits the current block and does the equivalent of enterblock <V> again.
> 
> <V> is an immediate operand, in SpiderMonkey a block object literal created by the compiler. It holds all
the bindings and their stack offsets, however many declarators with or without destructuring occur
after let.
> 
> I claim implementation is not the driver here. User expectations, esp. savvy users who might make some
practical or theoretical (testing) use of eta conversion, matter more.
Actually, I'm  more concerned about un-savy users who won't really understand the full semantics,
whatever we decide they are.

Allen
Domenic Denicola | 3 Feb 21:54
Gravatar

Array extras functionality for iterators

ES5's existing array extras make working with arrays a joy.

However, sometimes arrays are not the right tool for the job. Perhaps you want lazy evaluation semantics
(generators). Or perhaps you want to communicate that the list is immutable (compare .NET's
`IEnumerable<T>` or Java's `Iterable<T>`). ES Harmony seems to have the answer: iterators! Like
`IEnumerable<T>` or `Iterable<T>`, they are the most basic primitive of iteration. Yay!

But, if my `fetchAllProducts()` method returns an iterator, I don't get my array extras. Sad.

---

This may be solvable in library-space, but the iterator proposal doesn't seem to have an
Iterator.prototype I could extend. So we end up with unfortunate underscore-style wrappers:

_(iterator).chain().map(mapper).some(predicate).value()
_.some(_.map(iterator, mapper), predicate)

I propose adding the array extras to any iterator (in some way), such that we can have syntax similar to the following:

iterator.map(mapper).some(predicate) // returns an iterator

The methods I would like to see are:
* every, filter, forEach, map, reduce, reduceRight, some
* Optionally: join, toString
* Controversially: sorted, reversed (non-mutating versions of sort and reverse)

What do you think?

-Domenic

Gmane