Re: My ECMAScript 7 wishlist

2014-09-26 Thread Andrea Giammarchi
The only reason I've used `__noSuchProperty__` name in that example was to
indeed remind `__noSuchMethod__` and others anti-name-clashing old patterns
we all know but basically I was trying to explain that composing instead of
extending is a win for these kind of magic behaviors.

It is possible to use a Proxy without needing to go up to Object.prototype:

```js
// before creating instances of MyClass
// after MyClass definition ...
Object.setPrototypeOf(
  MyClass.prototype,
  withNoSuchPropertyProxy(
MyClass.prototype
  )
);
```

but what if we'd like to add more than one magic functionality ?

I also agree with Tab that is not so trivial to add is kind of
functionality the right way.

The old way ( I am not rehashing here, just explaining ) would have made
everything easy for developers:

```js
// easy ES3 shenanigans anti JIT
MyClass.prototype.__noSuchMethod__ = function (id, args) { ... };


// fast path via Symbols as ES6 likes them ...
MyClass.prototype[Symbol.noSuchProperty]= function (id) { ... };
```

Although using all these Symbols to simulate what traits would do in other
languages does not feel right.

About TC39 simplifying dev life, well ... isn't that the purpose of most
ES6 new features and sugar ?

So yes, there's some good intent and job going on here but few times I've
also read something like: it's hard for engines but there are APIs that
let you do that on JS side ... now, imagine how hard and potentially wrong
or slow would be in developers hands instead ...

As summary, I don't have a solution or a proposal for noSuchProperty and I
honestly don't feel the need for it (because Proxy) but I'd like to see
some discussion (in another thread maybe) about lightweight traits that are
also in Nicolas list (last point of his initial email)

Best Regards


On Fri, Sep 26, 2014 at 1:38 AM, Brendan Eich bren...@mozilla.org wrote:

 On Sep 25, 2014, at 7:56 PM, Boris Zbarsky bzbar...@mit.edu wrote:
 
  SpiderMonkey used to support __noSuchMethod__, I believe.

 I implemented __noSuchMethod__ long ago, for the TIBET folks (Smalltalk
 style JS framework; they wanted a doesNotUnderstand analogue).

 Please note well the difference between __noSuchMethod__ and anything like
 __noSuchProperty__. Even ignoring JITs, back in the interpreter only days,
 I could justify nSM because it was called on a slow path, when the only
 outcome without it was a guaranteed obj.foo is not callable or worse,
 obj.foo is not defined error.

 IOW nSM only kicked in when evaluating

 obj.foo(args)

 Not just

 obj.foo

 Any nSP of the kind we seem to be discussing would need to fail fast, on
 evaluation of the dot expression. That is a fast path.

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

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


Re: My ECMAScript 7 wishlist

2014-09-26 Thread Brendan Eich

Tab Atkins Jr. wrote:

I don't understand how you inferred from Andrea's post that this
wish-fulfillment __noSuchProperty__ magic property does not have to
handle superclass delegation..


I did not infer that from Andrea's post as his position -- rather the 
reverse, because he said I also think Proxy already gives us a way 
..., to wit the code I showed earlier. Hence my confusion about what 
was being proposed that differed.



   At minimum it needs to handle
delegating to the object's own prototype (it would be a pretty poor
NSP if it couldn't handle methodMissing use-cases as well), and I
don't think there's a reasonable case to stop at just one level up;
doing so would make this very fragile to refactoring your hierarchy,
as methods show up as missing or not depending on where they end up in
the class hierarchy.


Methinks you protest too much. Just put it below Object.prototype and 
get on with life. That was the idea, anyway.


Yes, what you propose is more flexible. Also more costly. Good luck 
selling implementors! I hope Andreas will comment now.


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


Re: My ECMAScript 7 wishlist

2014-09-26 Thread Dean Landolt
On Fri, Sep 26, 2014 at 10:29 AM, Brendan Eich bren...@mozilla.org wrote:

 Tab Atkins Jr. wrote:

 I don't understand how you inferred from Andrea's post that this
 wish-fulfillment __noSuchProperty__ magic property does not have to
 handle superclass delegation..


 I did not infer that from Andrea's post as his position -- rather the
 reverse, because he said I also think Proxy already gives us a way ...,
 to wit the code I showed earlier. Hence my confusion about what was being
 proposed that differed.

 At minimum it needs to handle
 delegating to the object's own prototype (it would be a pretty poor
 NSP if it couldn't handle methodMissing use-cases as well), and I
 don't think there's a reasonable case to stop at just one level up;
 doing so would make this very fragile to refactoring your hierarchy,
 as methods show up as missing or not depending on where they end up in
 the class hierarchy.


 Methinks you protest too much. Just put it below Object.prototype and get
 on with life. That was the idea, anyway.

 Yes, what you propose is more flexible. Also more costly. Good luck
 selling implementors! I hope Andreas will comment now.


Out of curiosity, wouldn't Object.observe require implementors to add
precisely this kind of hook into the vm anyway?
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: My ECMAScript 7 wishlist

2014-09-26 Thread Brendan Eich

Dean Landolt wrote:
Out of curiosity, wouldn't Object.observe require implementors to add 
precisely this kind of hook into the vm anyway?


No, but O.o has its own costs. See

http://lists.w3.org/Archives/Public/public-script-coord/2014JulSep/0204.html

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


Re: My ECMAScript 7 wishlist

2014-09-26 Thread Anne van Kesteren
On Fri, Sep 26, 2014 at 5:01 PM, Jason Orendorff
jason.orendo...@gmail.com wrote:
 On Thu, Sep 25, 2014 at 6:56 PM, Boris Zbarsky bzbar...@mit.edu wrote:
 SpiderMonkey used to support __noSuchMethod__, I believe.

 It's still there.

 js var anObject = { __noSuchMethod__() { return what; } };
 js anObject.saysWhat();
 what

https://bugzilla.mozilla.org/show_bug.cgi?id=683218 is the bug on
getting it removed, in case anyone is interested.


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


Re: My ECMAScript 7 wishlist

2014-09-26 Thread Brendan Eich

Brendan Eich wrote:

Dean Landolt wrote:
Out of curiosity, wouldn't Object.observe require implementors to add 
precisely this kind of hook into the vm anyway?


No, but O.o has its own costs. See

http://lists.w3.org/Archives/Public/public-script-coord/2014JulSep/0204.html 



To say a bit more, as Andreas wrote at the link above, O.o has 
multifarious costs todo with mutation and notification.


An unstratified and *general purpose* __noSuchProperty__ trap would 
impose costs on property sets as well as gets. Why as well as? Because 
of the override mistake where a prototype non-writable data property 
prevents assignment of a shadowing property; and where (symmetric to the 
data property case) a prototype accessor's setter must be called. If nSP 
is defined to do other than throw, e.g., to reify a property on demand 
from some peer property-space, then it must be called for both set and 
get in the missing case.


You could define nSP (maybe someone will, it's still tedious to guess 
here :-/) to apply only to get, but assuming it would work as its name 
and interface suggest -- for more than merely throwing an error when 
called -- I'm proceeding as if it must be called (if present) for 
missing in-not-own property on set as well as get.


The costs should accrue only if some object on the object at hand or 
along its prototype chain has nSP set on it, but that doesn't help much 
for implementors. Splitting out prototype chain walking for all gets and 
sets imposes high cost of code duplication and specialization in modern 
engines. So-called inline caches must be forked to handle both cases, if 
you want good performance for objects below the one with nSP.


Andreas can say more, but this general problem of pervasive costs and 
complications due to unstratified traps is exactly the reason we put 
metaprogramming APIs on Proxies, mostly (legacy accessors, good old o[x] 
for computed name x, and a few others aside).


(BTW, complaining about complexity of Proxy and Reflect is off topic, a 
move-the-goalposts attempt that makes me grumpy. Library code hides the 
details. The issue we're trying to get to is user-facing functionality, 
not implementation complexity inside the black box the user faces.)


When I say TC39 wanted to let the ecosystem handle this it was first 
and foremost about not rushing library design by committee, or even by 
champions, into a spec, when the the greater number of developers could 
do something better, search multiple paths in the design space, 
cooperate and compete, and meet the demand.


But there was also a desire not to jam more unstratified traps into 
objects, with their optimized hot paths. That's why proxies were added. 
If they can't meet the main use case that Nicholas had in mind, we 
should find out the hard way, from real code, not just from advance 
speculations.


If the main use case is to emulate (for one's own object-based 
abstractions) Python and other languages that do not allow obj.typo to 
pass without runtime error, then a library to add a proxy just below 
Object.prototype and above one's prototypal (constructor = class) 
hierarchy might be enough. It won't satisfy all possible use-cases, but 
that's a positive if it hits the main target and spares us unstratified 
traps hitting hot paths.


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


Re: My ECMAScript 7 wishlist

2014-09-26 Thread Brendan Eich

Dean Landolt wrote:



http://lists.w3.org/Archives/Public/public-script-coord/2014JulSep/0204.html



Sure, O.o isn't free, and I get that using @noSuchProperty would 
likely result in all kinds of deoptimization. But of all the costs 
listed in that thread, I'm not seeing any mention of the cost of 
intercepting changes for notification queueing.


You may have missed these points, then:



Finally, just to clear up some myths, observation is nothing close to
free inside V8 either:

- Observing an object slows down all its mutations severely, easily by
10x-100x, depending on the case.

- It invalidates a range of routine optimisations, especially for bulk
mutations like on arrays. Essentially, observing an object forces
every potentially impure operation on it onto the slowest path.

- Observation introduces additional type polymorphism, which can cause
even unrelated optimisations to fall off the cliff.

Most of these costs are inherent to the mechanism, and there probably
isn't much of a chance that they can be optimised by more than
constant factors.

/Andreas



I'm assuming this has to be part of any O.o implementation (IIUC the 
only alternative would be polling observed objects every turn). More 
importantly that must already paid for all observed objects. You made 
the comment Good luck selling implementors, and I was just wondering 
aloud whether they've already been sold on doing the heavy lifting for 
the sake of O.o.


See my longer followup. A general-purpose (as its name implies) nSP 
would hit lookup (get as well as set) paths, not just mutation (set). 
But it seems Andreas's just to clear up some myths words were missed, 
even considering only mutation (not notification).


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


Re: My ECMAScript 7 wishlist

2014-09-26 Thread Brendan Eich

Brendan Eich wrote:
A general-purpose (as its name implies) nSP would hit lookup (get as 
well as set) paths, not just mutation (set). But it seems Andreas's 
just to clear up some myths words were missed, even considering only 
mutation (not notification). 


From private correspondence with Dean, it seems the cost of O.o (bad 
enough that the web platform cannot use it all over) may be assumed to 
be no better and not much worse than the cost of nSP. This isn't the 
case, nSP is strictly costlier and more complicated than O.o.


In JS, `set` applies after prototype chain walking (to find the setter, 
or the non-writable data property [in which case error], or to decide to 
make an own property on the directly referenced object). Call the proto 
walk step `lookup`.


`get` is more common than `set` but both require `lookup`, with differences.

O.o hits `set` but nSP hits `lookup` so affects both reading and writing.

A narrow throw-only nSP, say __throwOnNoSuchProperty__ with boolean 
value, would hit only the `get`-driven `lookup` paths. Still costlier in 
dynamic frequency and static code complexity than O.o, but much more 
targeted and (I think) optimizable. Need Andreas Rossberg and others to 
weigh in.


The pay only if you use nSP or O.o argument has limits. O.o got into 
Harmony on that basis, but then the myth that it was cheap enough to use 
all over the web platform grew -- bad myth, Andreas busted it.


A general nSP risks similar myth or hype-cycle and won't be optimized 
enough to stick, any more than O.o will, per Andreas's final Most of 
these costs are inherent to the mechanism, and there probably isn't much 
of a chance that they can be optimised by more than constant factors.


This implementation complexity and perf cost issue is not just about 
implementor burden. It changes naive user-(myth)understood economics and 
adds attractive nuisance risk. But just considering VM costs (code and 
runtime), it's a big deal.


A Proxy on a prototype chain, in contrast, modularizes the hit. It 
deoptimizes without multiplying `lookup` paths by two. The cost of host 
objects and proxies on prototypes has already been sunk, since you could 
make such chains even in 18 years ago.


I don't like it when implementor vs. user trade-offs fight in what seems 
like a zero-sum game. I'm Captain Kirk, I don't believe in the no-win 
scenario. (How'd that end? Ignore the retread/remake with role reversal!)


But in this case both implementors and users are facing physics. If the 
root post in this thread wants only an error for obj.typo, we shouldn't 
be chasing nSP, which is unstratified and over-general. We should try 
the proxy-in-library-clothing path and if it is too painful, consider 
some targeted and optimizable fix.


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


Re: My ECMAScript 7 wishlist

2014-09-26 Thread Tab Atkins Jr.
On Thu, Sep 25, 2014 at 5:38 PM, Brendan Eich bren...@mozilla.org wrote:
 On Sep 25, 2014, at 7:56 PM, Boris Zbarsky bzbar...@mit.edu wrote:

 SpiderMonkey used to support __noSuchMethod__, I believe.

 I implemented __noSuchMethod__ long ago, for the TIBET folks (Smalltalk style 
 JS framework; they wanted a doesNotUnderstand analogue).

 Please note well the difference between __noSuchMethod__ and anything like 
 __noSuchProperty__. Even ignoring JITs, back in the interpreter only days, I 
 could justify nSM because it was called on a slow path, when the only outcome 
 without it was a guaranteed obj.foo is not callable or worse, obj.foo is 
 not defined error.

 IOW nSM only kicked in when evaluating

 obj.foo(args)

 Not just

 obj.foo

 Any nSP of the kind we seem to be discussing would need to fail fast, on 
 evaluation of the dot expression. That is a fast path.

I, personally, have only ever used Python and PHP's nSP functionality
to implement methods.  Most of the fancy uses I see for it in, say,
Ruby (like the cool dynamic query methods on ORMs), are also methods.
There are certainly uses for this kind of functionality for non-method
properties, but I suspect just going with noSuchMethod would satisfy
most use-cases.  I'd certainly be happier with that. ^_^

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


Re: My ECMAScript 7 wishlist

2014-09-26 Thread Brendan Eich

Tab Atkins Jr. wrote:

Any nSP of the kind we seem to be discussing would need to fail fast, on 
evaluation of the dot expression. That is a fast path.


I, personally, have only ever used Python and PHP's nSP functionality
to implement methods.  Most of the fancy uses I see for it in, say,
Ruby (like the cool dynamic query methods on ORMs), are also methods.
There are certainly uses for this kind of functionality for non-method
properties, but I suspect just going with noSuchMethod would satisfy
most use-cases.  I'd certainly be happier with that. ^_^


__noSuchMethod__ is not what Nicholas sketched on his wishlist, though.

There are two valid use-cases/proposals:

1. Smalltalk doesNotUnderstand (but Smalltalk makes everything a method 
selected by a message, no get vs. invoke [get+call] distinction), which 
led to SpiderMonkey's __noSuchMethod__. This is an unstratified trap to 
handle obj.foo() but not obj.foo -- in JS, whether it handles `do { let 
f = obj.foo; f(); }` is a good question.


2. Nicholas's request for a way to make obj.typo an error. I wish I had 
a nickel for every time someone new to JS asked me for this since 1995 
(or perhaps 1998 when try-catch was done). This is all about failing 
fast on typo'ed or otherwise missing property references, gets as well 
as get+calls.


These are two distinct things. You should start a new thread if you want 
(1). But we've been over it several times already:


https://www.google.com/search?q=site%3Aesdiscuss.org+noSuchMethod

What new helium do you have this time to get __noSuchMethod__ airborne? 
The Proxy-based library solution from Tom Van Cutsem at


http://esdiscuss.org/topic/nosuchmethod-and-direct-proxies

is sucking heavier gasses out of the air around you :-P.

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


Re: My ECMAScript 7 wishlist

2014-09-25 Thread Tab Atkins Jr.
On Wed, Sep 24, 2014 at 3:28 PM, Brendan Eich bren...@mozilla.org wrote:
 Tab Atkins Jr. wrote:

 Using subclassing to bung in some arbitrary trait is really terrible.
 :/  It requires either adding it up high in your class hierarchy, or
 having to write a custom NoSuchPropertyClass which extends your
 superclass, so you can then extend it.

 Ok, let's not hand-wave mixin syntax, though (Andrea hacks __proto__). What
 API do you prefer?

I'm partial to magic-named functions, but that's probably my
experience speaking, rather than a more thoughtful opinion.
Symbol-named magic functions would be better, since we have those and
most other languages don't.

Andrea wasn't even hacking __proto__ - they're just adding it to the
class prototype, so newly constructed objects'll have it.

 I'm rather surprised that the group actually considered that sort of
 code to be appropriate - it's known that it doesn't compose well with
 other traits-as-superclasses or normal subclassing.

 What code was not appropriate? TC39 balked at standardizing library API, and
 good for them. You want better API, design it!

The use of a Proxy superclass to implement the functionality, which
you demonstrated in an earlier email.

 Or did you want `sealed class` or other such syntax, and I misunderstood?

Nah, using superclasses in general is the bad thing here; it doesn't
compose well without multi-inheritance, which JS likely isn't going to
do.

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


Re: My ECMAScript 7 wishlist

2014-09-25 Thread Tab Atkins Jr.
On Thu, Sep 25, 2014 at 12:50 PM, Brendan Eich bren...@mozilla.org wrote:
 Tab Atkins Jr. wrote:
If you try to add it in a targeted way in the middle of
 your hierarchy, it requires either __proto__ hacking, something like:

 class superclass {...}
 ...
 x = makeNSPProxy()
 x.__proto__ = superclass()
 class subclass extends x {...}


 (In such code, you need x to be a function with .prototype that is the
 proxy, as just up-thread at

 https://mail.mozilla.org/pipermail/es-discuss/2014-September/039565.html

 but no big deal.)

 Yes, the proxy's get handler must deal with superclasses other than Object,
 if that's required.

 The requirements aren't clear (we're probably assuming something that
 doesn't match what developers want in full), but that's the point: TC39 is
 not the library designer droid you're looking for.

 On the other hand, a magic property can be placed exactly where you
 want it, without any difficulty.


 No one made a coherent proposal for the magic property. It was not clear
 from Andrea's latest post, where he even allows

 I also think Proxy already gives us a way to work around the
 `__noSuchProperty__` issue

 that this wish-fulfillment __noSuchProperty__ magic property does not have
 to handle superclass delegation.

 So please define the magic property fully before recommending it as better
 than the Proxy-based library approach. How would it work? The engine calls
 the function value of this magic property only when the object on which it
 is set has no such *own* property?

 If so, then the handler function must not throw if some superclass contains
 the wanted name. Just as the Proxy get handler I showed does for
 Object.prototype.

 If not, then does the magic property trigger only when the object on which
 it is set *and every object on its prototype chain* has no such property?
 That is a bit nasty on the JS engine optimized lookup side, but perhaps
 implementors should work harder so users don't have to.

 Is that what you're proposing? Then we should summon optimizing engine
 hackers. I've cc'ed one :-P.

Yes, that is what I'm proposing.  If lookup fails completely (reaches
Object.prototype without finding the named property), it then does a
second lookup for the magic NSP property, and if it finds it, executes
it with the property name, returning the return value as the result of
the original lookup.

I don't understand how you inferred from Andrea's post that this
wish-fulfillment __noSuchProperty__ magic property does not have to
handle superclass delegation..  At minimum it needs to handle
delegating to the object's own prototype (it would be a pretty poor
NSP if it couldn't handle methodMissing use-cases as well), and I
don't think there's a reasonable case to stop at just one level up;
doing so would make this very fragile to refactoring your hierarchy,
as methods show up as missing or not depending on where they end up in
the class hierarchy.

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


Re: My ECMAScript 7 wishlist

2014-09-25 Thread Boris Zbarsky

On 9/25/14, 4:31 PM, Tab Atkins Jr. wrote:

Yes, that is what I'm proposing.  If lookup fails completely (reaches
Object.prototype without finding the named property), it then does a
second lookup for the magic NSP property, and if it finds it, executes
it with the property name, returning the return value as the result of
the original lookup.


SpiderMonkey used to support __noSuchMethod__, I believe.

It was removed because it caused problems for the JIT (in addition to 
being non-standard, etc, etc).  Might be worth looking into what those 
were, exactly, before we consider standardizing something like this.


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


Re: My ECMAScript 7 wishlist

2014-09-25 Thread Brendan Eich
On Sep 25, 2014, at 7:56 PM, Boris Zbarsky bzbar...@mit.edu wrote:
 
 SpiderMonkey used to support __noSuchMethod__, I believe.

I implemented __noSuchMethod__ long ago, for the TIBET folks (Smalltalk style 
JS framework; they wanted a doesNotUnderstand analogue).

Please note well the difference between __noSuchMethod__ and anything like 
__noSuchProperty__. Even ignoring JITs, back in the interpreter only days, I 
could justify nSM because it was called on a slow path, when the only outcome 
without it was a guaranteed obj.foo is not callable or worse, obj.foo is not 
defined error.

IOW nSM only kicked in when evaluating

obj.foo(args)

Not just

obj.foo

Any nSP of the kind we seem to be discussing would need to fail fast, on 
evaluation of the dot expression. That is a fast path.

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


Re: My ECMAScript 7 wishlist

2014-09-24 Thread Brendan Eich

Brendan Eich wrote:

Tab Atkins Jr. wrote:

This works great as a general principle, but honestly tons of
languages have already forged this path.  It's pretty straightforward,
I think.


I made the case for building it in sooner, but TC39 wanted less 
sooner based on library usage. There was a minority position (as 
voiced; could be majority) that argued JS is different, object 
detection plus optional fields means this is the wrong direction. 


Not trying to be controversial ;-). Would you use ES6 classes and have 
the ones you wrote all extend NoSuchPropertyClass?


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


Re: My ECMAScript 7 wishlist

2014-09-24 Thread Tab Atkins Jr.
On Wed, Sep 24, 2014 at 2:56 PM, Brendan Eich bren...@mozilla.org wrote:
 Brendan Eich wrote:

 Tab Atkins Jr. wrote:

 This works great as a general principle, but honestly tons of
 languages have already forged this path.  It's pretty straightforward,
 I think.


 I made the case for building it in sooner, but TC39 wanted less sooner
 based on library usage. There was a minority position (as voiced; could be
 majority) that argued JS is different, object detection plus optional
 fields means this is the wrong direction.

 Not trying to be controversial ;-). Would you use ES6 classes and have the
 ones you wrote all extend NoSuchPropertyClass?

Using subclassing to bung in some arbitrary trait is really terrible.
:/  It requires either adding it up high in your class hierarchy, or
having to write a custom NoSuchPropertyClass which extends your
superclass, so you can then extend it.

I'm rather surprised that the group actually considered that sort of
code to be appropriate - it's known that it doesn't compose well with
other traits-as-superclasses or normal subclassing.

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


Re: My ECMAScript 7 wishlist

2014-09-24 Thread Andrea Giammarchi
Agreed with Tab, in terms of composing inherited functionality it's hard to
beat prototypal and the ease of `Class.prototype.__noSuchProperty__ =
function(){ ... };` traitish approach.

I also think Proxy already gives us a way to work around the
`__noSuchProperty__` issue

On Wed, Sep 24, 2014 at 11:17 PM, Tab Atkins Jr. jackalm...@gmail.com
wrote:

 On Wed, Sep 24, 2014 at 2:56 PM, Brendan Eich bren...@mozilla.org wrote:
  Brendan Eich wrote:
 
  Tab Atkins Jr. wrote:
 
  This works great as a general principle, but honestly tons of
  languages have already forged this path.  It's pretty straightforward,
  I think.
 
 
  I made the case for building it in sooner, but TC39 wanted less sooner
  based on library usage. There was a minority position (as voiced; could
 be
  majority) that argued JS is different, object detection plus optional
  fields means this is the wrong direction.
 
  Not trying to be controversial ;-). Would you use ES6 classes and have
 the
  ones you wrote all extend NoSuchPropertyClass?

 Using subclassing to bung in some arbitrary trait is really terrible.
 :/  It requires either adding it up high in your class hierarchy, or
 having to write a custom NoSuchPropertyClass which extends your
 superclass, so you can then extend it.

 I'm rather surprised that the group actually considered that sort of
 code to be appropriate - it's known that it doesn't compose well with
 other traits-as-superclasses or normal subclassing.

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

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


Re: My ECMAScript 7 wishlist

2014-09-24 Thread Brendan Eich

Tab Atkins Jr. wrote:

Using subclassing to bung in some arbitrary trait is really terrible.
:/  It requires either adding it up high in your class hierarchy, or
having to write a custom NoSuchPropertyClass which extends your
superclass, so you can then extend it.


Ok, let's not hand-wave mixin syntax, though (Andrea hacks __proto__). 
What API do you prefer?



I'm rather surprised that the group actually considered that sort of
code to be appropriate - it's known that it doesn't compose well with
other traits-as-superclasses or normal subclassing.


What code was not appropriate? TC39 balked at standardizing library API, 
and good for them. You want better API, design it!


Or did you want `sealed class` or other such syntax, and I misunderstood?

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


Re: My ECMAScript 7 wishlist

2014-09-23 Thread Brendan Eich
Hi Nicholas, sorry for the tardy reply. I did propose NoSuchProperty to 
Ecma TC39 today. To recap:


// Library code starts here.

const NoSuchProperty = Proxy(Object.prototype, {
  // uncomment for nasty Firefox bug workaround:
  // has: function(target, name) { return true; },
  get: function(target, name, receiver) {
if (name in Object.prototype) {
  return Reflect.get(Object.prototype, name, receiver);
}
throw new TypeError(name +  is not a defined property);
  }
});

function NoSuchPropertyClass() {}
NoSuchPropertyClass.prototype = NoSuchProperty;

// End library code.
// Your client code starts here.

class MySaferClass extends NoSuchPropertyClass {
  ...
}

The library code is self-hosted based on ES6 Proxies and Reflect.

The committee reaction was to let this be put in popular libraries, in 
forms to be polished based on actual developer experience, and then we 
can standardize once there is a clear winner and strong adoption.


Hope this is survivable. I argued we should shortcut to reduce the 
burden on the ecosystem but (as I've argued many times) TC39 believes we 
are least capable compared to the wider ecosystem (github, etc.) in 
designing, user-testing, polishing, and finalizing APIs. We can do final 
polish and formal specification, for sure. Y'all should do the hard 
part, not because we are lazy but because you are many, closer to your 
problem domains and use-cases, and collectively wiser about the details.


/be

Brendan Eich wrote:
Just FTR, I'll put a ratioanlized ES7 proposal on the agenda for the 
July TC39 meeting, as per


https://twitter.com/BrendanEich/status/475067783282057216

Thanks to Nicholas for the suggestion!

/be

Brendan Eich wrote:

Nicholas C. Zakas wrote:
It can be done with Proxy, but that kind of sucks because I always 
need to go through the extra step of creating the Proxy for each 
object and passing around the Proxy instead. To me, this is similar 
to setting a property to be readonly in strict mode, except its 
writeonly (or rather, write-first).


What about the code I showed, which shows a singleton being spliced 
high on many objects' prototype chains to handle the missing property 
throw?


js var NoSuchProperty = Proxy({}, {
  has: function(target, name) { return true; },
  get: function(target, name, receiver) {
if (name in Object.prototype) {
  return Reflect.get(Object.prototype, name, receiver);
}
throw new TypeError(name +  is not a defined property);
  }
});
js var obj = Object.create(NoSuchProperty)
js obj.foo = 42
42
js obj.foo
42
js obj.bar
/tmp/p.js:7:4 TypeError: bar is not a defined property

You could avoid Object.create by assigning to a 
Constructor.prototype, or hacking with __proto__, of course.


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


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


Re: My ECMAScript 7 wishlist

2014-09-23 Thread Tab Atkins Jr.
On Tue, Sep 23, 2014 at 2:34 PM, Brendan Eich bren...@mozilla.org wrote:
 Hi Nicholas, sorry for the tardy reply. I did propose NoSuchProperty to Ecma
 TC39 today. To recap:

 // Library code starts here.

 const NoSuchProperty = Proxy(Object.prototype, {
   // uncomment for nasty Firefox bug workaround:
   // has: function(target, name) { return true; },
   get: function(target, name, receiver) {
 if (name in Object.prototype) {
   return Reflect.get(Object.prototype, name, receiver);
 }
 throw new TypeError(name +  is not a defined property);
   }
 });

 function NoSuchPropertyClass() {}
 NoSuchPropertyClass.prototype = NoSuchProperty;

 // End library code.
 // Your client code starts here.

 class MySaferClass extends NoSuchPropertyClass {
   ...
 }

 The library code is self-hosted based on ES6 Proxies and Reflect.

 The committee reaction was to let this be put in popular libraries, in forms
 to be polished based on actual developer experience, and then we can
 standardize once there is a clear winner and strong adoption.

 Hope this is survivable. I argued we should shortcut to reduce the burden on
 the ecosystem but (as I've argued many times) TC39 believes we are least
 capable compared to the wider ecosystem (github, etc.) in designing,
 user-testing, polishing, and finalizing APIs. We can do final polish and
 formal specification, for sure. Y'all should do the hard part, not because
 we are lazy but because you are many, closer to your problem domains and
 use-cases, and collectively wiser about the details.

This works great as a general principle, but honestly tons of
languages have already forged this path.  It's pretty straightforward,
I think.

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


Re: My ECMAScript 7 wishlist

2014-09-23 Thread Brendan Eich

Tab Atkins Jr. wrote:

This works great as a general principle, but honestly tons of
languages have already forged this path.  It's pretty straightforward,
I think.


I made the case for building it in sooner, but TC39 wanted less sooner 
based on library usage. There was a minority position (as voiced; could 
be majority) that argued JS is different, object detection plus optional 
fields means this is the wrong direction.


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


Re: My ECMAScript 7 wishlist

2014-06-15 Thread Brendan Eich

Andrea Giammarchi wrote:
In such case the only concern would be why `Object.prototype` is 
considered but not inherited properties too.


Because NoSuchProperty is meant to be inserted just before 
Object.prototype, avoiding that loop.


What's more, the loop is unnecessary:

var NoSuchProperty = Proxy({}, {
  get: function(target, name, receiver) {
while (target = Object.getPrototypeOf(target)) {
  if (name in target) {
return Reflect.get(target, name, receiver);
  }
}
throw new TypeError(name +  is not a defined property);
  }
});


If NoSuchProperty is inserted just before Object.prototype on a chain of 
ordinary objects, its get handler won't be invoked until no such 
property is indeed found along the path from the original target to 
NoSuchProperty. Therefore all iterations but the last (where target is 
Object.prototype) are redundant.


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


Re: My ECMAScript 7 wishlist

2014-06-15 Thread Andrea Giammarchi
 Because NoSuchProperty is meant to be inserted just before
Object.prototype

I miss this constrain, wouldn't have bothered with the loop otherwise.

Regards


On Sun, Jun 15, 2014 at 11:27 AM, Brendan Eich bren...@mozilla.org wrote:

 Andrea Giammarchi wrote:

 In such case the only concern would be why `Object.prototype` is
 considered but not inherited properties too.


 Because NoSuchProperty is meant to be inserted just before
 Object.prototype, avoiding that loop.

 What's more, the loop is unnecessary:


 var NoSuchProperty = Proxy({}, {
   get: function(target, name, receiver) {
 while (target = Object.getPrototypeOf(target)) {
   if (name in target) {
 return Reflect.get(target, name, receiver);
   }
 }
 throw new TypeError(name +  is not a defined property);
   }
 });


 If NoSuchProperty is inserted just before Object.prototype on a chain of
 ordinary objects, its get handler won't be invoked until no such property
 is indeed found along the path from the original target to NoSuchProperty.
 Therefore all iterations but the last (where target is Object.prototype)
 are redundant.

 /be

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


Re: My ECMAScript 7 wishlist

2014-06-07 Thread André Bargull

that `has:()=true` breaks with features detections that are meant to be
less obtrusive than getters ... i.e. `'geolocation' in navigator` or
`'innerHTML' in genericNode` and all others that are not supposed to pass
through a potentially expensive getter to retrieve a feature detection
purpose info.

Long story short that NoSuchProperty is obtrusive in an upside-down way ...
I personally would not use that and would not expect that anywhere


The 'has' handler is required to work around a Firefox limitation. A 
compliant ES6 implementation only needs the 'get' handler.


Related bug reports:
https://bugzilla.mozilla.org/show_bug.cgi?id=914314
https://bugzilla.mozilla.org/show_bug.cgi?id=1009199
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: My ECMAScript 7 wishlist

2014-06-07 Thread Andrea Giammarchi
Interesting bug, thanks for the info.

In such case the only concern would be why `Object.prototype` is considered
but not inherited properties too.

If inheritance should be considered, I'd rather go like this:

```
var NoSuchProperty = Proxy({}, {
  get: function(target, name, receiver) {
while (target = Object.getPrototypeOf(target)) {
  if (name in target) {
return Reflect.get(target, name, receiver);
  }
}
throw new TypeError(name +  is not a defined property);
  }
});
```

Best Regards




On Sat, Jun 7, 2014 at 1:42 AM, André Bargull andre.barg...@udo.edu wrote:

 that `has:()=true` breaks with features detections that are meant to be
 less obtrusive than getters ... i.e. `'geolocation' in navigator` or
 `'innerHTML' in genericNode` and all others that are not supposed to pass
 through a potentially expensive getter to retrieve a feature detection
 purpose info.

 Long story short that NoSuchProperty is obtrusive in an upside-down way
 ...
 I personally would not use that and would not expect that anywhere


 The 'has' handler is required to work around a Firefox limitation. A
 compliant ES6 implementation only needs the 'get' handler.

 Related bug reports:
 https://bugzilla.mozilla.org/show_bug.cgi?id=914314
 https://bugzilla.mozilla.org/show_bug.cgi?id=1009199

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


Re: My ECMAScript 7 wishlist

2014-06-06 Thread David Bruant

Le 06/06/2014 01:08, Rick Waldron a écrit :
On Thu, Jun 5, 2014 at 6:42 PM, Nicholas C. Zakas 
standa...@nczconsulting.com mailto:standa...@nczconsulting.com wrote:


* `Object.deepPreventExtensions()`, `Object.deepSeal()`,
`Object.deepFreeze()` - deep versions of
`Object.preventExtensions()`, et al.


Does deep mean that a Map instance's [[MapData]] is frozen if 
deepFreeze is called on a ? eg. what happens here:


var m = Object.deepFreeze(new Map());
m.set(1, 1);
I think the intention behind Object.freeze was to make objects immutable 
(at a shallow level), so maybe the semantics of Map.prototype.set (and 
all modifying operations, of Mapco) should be changed to read the 
[[IsExtensible]] and throw if false is returned. Given Maps are already 
in the wild, this decision might need to be taken quickly.


or should an Object.makeImmutable be introduced? (it would be freeze + 
make all internal [[*Data]] objects immutable)



* `Object.preventUndeclaredGet()` - change an object's behavior to
throw an error if you try to read from a property that doesn't
exist (instead of returning `undefine`).

(I already know that Nicholas and I disagree on the topic, but sharing 
for debating).



This can be achieved with Proxy right, or is that too cumbersome?
Code-readability-wise, wrapping in a proxy is as cumbersome as a call to 
Object.preventUndeclaredGet I guess.


This sort of concerns are only development-time concerns and I believe 
the runtime shouldn't be bothered with these (I'm aware it already is in 
various web). For instance, the TypeScript compiler is capable today of 
catching this error. Given that we have free, cross-platform and fairly 
easy to use tools, do we need assistance from the runtime?


David

[1] https://twitter.com/passy/status/469127322072014849
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: My ECMAScript 7 wishlist

2014-06-06 Thread Mark S. Miller
On Fri, Jun 6, 2014 at 5:44 AM, David Bruant bruan...@gmail.com wrote:

  Le 06/06/2014 01:08, Rick Waldron a écrit :

 On Thu, Jun 5, 2014 at 6:42 PM, Nicholas C. Zakas 
 standa...@nczconsulting.com wrote:

  * `Object.deepPreventExtensions()`, `Object.deepSeal()`,
 `Object.deepFreeze()` - deep versions of `Object.preventExtensions()`, et
 al.


  Does deep mean that a Map instance's [[MapData]] is frozen if
 deepFreeze is called on a ? eg. what happens here:

  var m = Object.deepFreeze(new Map());
 m.set(1, 1);

 I think the intention behind Object.freeze was to make objects immutable
 (at a shallow level), so maybe the semantics of Map.prototype.set (and all
 modifying operations, of Mapco) should be changed to read the
 [[IsExtensible]] and throw if false is returned. Given Maps are already in
 the wild, this decision might need to be taken quickly.


The main intention of Object.freeze is to make objects tamper proof. To
ensure that their API surface is only according to the provider, not to the
clients, and thereby prevent client A from corrupting the API seen by
client B. This is why Object.freeze has no effect on non-configurable
accessor properties -- their writable-property-like behavior is fully in
control of the abstraction provider.

Of course, it does also cause some further immutability beyond that initial
purpose, and so there become valid purposes too. The API surface of an
array consists of data properties, so freezing an array turns it into a
shallowly immutable array. Typed Arrays refuse to be frozen as of ES6. Post
ES6, perhaps we will enable them to be frozen, resulting in their indexed
properties being immutable, since these are presented as data properties.
Were we allow these to be frozen, they would also become un-neuterable,
which means they would be passed over postMessage by sharing of the
underlying data, rather than by ownership transfer of that data, which is
exactly what you want once the data is immutable.

By contrast, a Map's state is more like the private instance variable state
of a closure or a post-ES6 class. Object.freeze of a Map should not alter
the mutability of this state for the same reason it does not alter the
state captured by a closure or a future class instance.


 or should an Object.makeImmutable be introduced? (it would be freeze +
 make all internal [[*Data]] objects immutable)


We do need something like that. But it's a bit tricky. A client of an
object should not be able to attack it by preemptively deep-freezing it
against its wishes.





 * `Object.preventUndeclaredGet()` - change an object's behavior to throw
 an error if you try to read from a property that doesn't exist (instead of
 returning `undefine`).

   (I already know that Nicholas and I disagree on the topic, but sharing
 for debating).



Once again, perhaps it is something that the provider of an object could
determine, but it shouldn't be something up to an object's clients. But
like you observe below, we can already do this with a proxy, so let's not
introduce a second mechanism without a compelling reason.

And the proxy solution wraps the initial object, rather than changing its
behavior in place, so it does not enable one client to corrupt the behavior
seen by other clients.



   This can be achieved with Proxy right, or is that too cumbersome?

 Code-readability-wise, wrapping in a proxy is as cumbersome as a call to
 Object.preventUndeclaredGet I guess.

 This sort of concerns are only development-time concerns and I believe the
 runtime shouldn't be bothered with these (I'm aware it already is in
 various web). For instance, the TypeScript compiler is capable today of
 catching this error. Given that we have free, cross-platform and fairly
 easy to use tools, do we need assistance from the runtime?


Yes. Object.freeze is a runtime production protection mechanism, because
attacks that are only prevented during development don't matter very much
;).




 David

 [1] https://twitter.com/passy/status/469127322072014849

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




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


Re: My ECMAScript 7 wishlist

2014-06-06 Thread David Bruant

Le 06/06/2014 15:57, Mark S. Miller a écrit :
By contrast, a Map's state is more like the private instance variable 
state of a closure or a post-ES6 class.
The capabilities to arbitrarily modify Maps (set/delete on all keys, 
with any values) will be expected by any ES6-compliant code to be 
globally available, so a Map's state cannot reasonably be considered 
private.
This differs from the state of a closure where its access is strictly 
moderated by the public API giving access to it and to the fact that 
this API is not provided globally (unlike Map.prototype).


Object.freeze of a Map should not alter the mutability of this state 
for the same reason it does not alter the state captured by a closure 
or a future class instance.
I'd argue the Map state is very much like regular objects (for which you 
can't deny [[Set]], [[Delete]], etc.), not closure's state.


In an ES6 world, denying access to the global Map.prototype.* would 
break legitimate code, so that's not really an option confiners like 
Caja could provide.





or should an Object.makeImmutable be introduced? (it would be
freeze + make all internal [[*Data]] objects immutable)


We do need something like that. But it's a bit tricky. A client of an 
object should not be able to attack it by preemptively deep-freezing 
it against its wishes.

I don't see the difference with shallow-freezing?
It's currently not possible to defend against shallow-freezing (it will 
be possible via wrapping in a proxy).





This can be achieved with Proxy right, or is that too cumbersome?

Code-readability-wise, wrapping in a proxy is as cumbersome as a
call to Object.preventUndeclaredGet I guess.

This sort of concerns are only development-time concerns and I
believe the runtime shouldn't be bothered with these (I'm aware it
already is in various web). For instance, the TypeScript compiler
is capable today of catching this error. Given that we have free,
cross-platform and fairly easy to use tools, do we need assistance
from the runtime?


Yes. Object.freeze is a runtime production protection mechanism, 
because attacks that are only prevented during development don't 
matter very much ;).
Just to clarify, I agree that Object.freeze was necessary in ES5 (have 
we had proxies, it might have been harder to justify?), because there 
was no good alternative to protect an object against the parties it was 
shared with.
But the concern Nicholas raises doesn't seem to have this property. 
Reading a property that doesn't exist doesn't carry a security risk, 
does it? Object.preventUndeclaredGet doesn't really protect against 
anything like ES5 methods did.


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


Re: My ECMAScript 7 wishlist

2014-06-06 Thread Mark S. Miller
On Fri, Jun 6, 2014 at 7:37 AM, David Bruant bruan...@gmail.com wrote:

  Le 06/06/2014 15:57, Mark S. Miller a écrit :

 By contrast, a Map's state is more like the private instance variable
 state of a closure or a post-ES6 class.

 The capabilities to arbitrarily modify Maps (set/delete on all keys, with
 any values) will be expected by any ES6-compliant code to be globally
 available, so a Map's state cannot reasonably be considered private.
 This differs from the state of a closure where its access is strictly
 moderated by the public API giving access to it and to the fact that this
 API is not provided globally (unlike Map.prototype).


That's a good point, but doesn't really address what I'm trying to say. The
map's state is manipulable through its API surface, rather than being the
properties which are its API surface. In the abstract perhaps this is a
subtle distinction, but it is the distinction Object.freeze is built on.

Consider if you wrote in JavaScript a Map abstraction of your own that held
the data structures of your map implementation in private instance
variables. Object.freeze would clearly not touch your map implementation.
For builtins, internal properties serve the role that private instance
variables will in class instances.

This does bring up an interesting issue though. Even if you wanted your map
to respond to Object.freeze by making this internal implementation be no
longer mutable, you can't, unless the Map is a proxy, because no other JS
object can sense when it is being frozen. More on this in another email
coming soon.

  Object.freeze of a Map should not alter the mutability of this state for
 the same reason it does not alter the state captured by a closure or a
 future class instance.

 I'd argue the Map state is very much like regular objects (for which you
 can't deny [[Set]], [[Delete]], etc.), not closure's state.

 In an ES6 world, denying access to the global Map.prototype.* would break
 legitimate code, so that's not really an option confiners like Caja could
 provide.


Why would we want to deny access to Map.prototype.* ? If there were a Map
among the primordials, for example, if Map.prototype itself were a Map,
then, in combination with the primordial existence of Map.prototype.set,
we'd have a global communications channel. (Indeed, SES repairs
Date.prototype when Data.prototype is a Date, and likewise for WeakMap 
https://code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/repairES5.js#2806
https://bugzilla.mozilla.org/show_bug.cgi?id=861219.)



 or should an Object.makeImmutable be introduced? (it would be freeze +
 make all internal [[*Data]] objects immutable)


  We do need something like that. But it's a bit tricky. A client of an
 object should not be able to attack it by preemptively deep-freezing it
 against its wishes.

 I don't see the difference with shallow-freezing?
 It's currently not possible to defend against shallow-freezing (it will be
 possible via wrapping in a proxy).


Therefore a defensible API surface in JS cannot contain as part of its
contract that it presents data properties that remain writable. Except as
you point out, for proxies which refuse to be frozen. This restriction on
the possibilities for defensible API surfaces is an unfortunate consequence
of the unpleasant choices we had for securing ES5, as you point out below.


  This can be achieved with Proxy right, or is that too cumbersome?

  Code-readability-wise, wrapping in a proxy is as cumbersome as a call to
 Object.preventUndeclaredGet I guess.

 This sort of concerns are only development-time concerns and I believe
 the runtime shouldn't be bothered with these (I'm aware it already is in
 various web). For instance, the TypeScript compiler is capable today of
 catching this error. Given that we have free, cross-platform and fairly
 easy to use tools, do we need assistance from the runtime?


  Yes. Object.freeze is a runtime production protection mechanism, because
 attacks that are only prevented during development don't matter very much
 ;).

 Just to clarify, I agree that Object.freeze was necessary in ES5 (have we
 had proxies, it might have been harder to justify?), because there was no
 good alternative to protect an object against the parties it was shared
 with.


Exactly. But even with proxies, proxies are way way too heavy to be the
only form of defensible object. ES6 classes also give us a place to stand
to start to talk about the difference between provider and client.
Hopefully ES7 will support defensible classes that make defensible
instances. But because of the historical path these decisions took, I
expect that this class-based defensiveness will only be sugar for a pattern
of freezing anyway, so it won't make a fundamental difference.



 But the concern Nicholas raises doesn't seem to have this property.
 Reading a property that doesn't exist doesn't carry a security risk, does
 it? Object.preventUndeclaredGet doesn't 

Re: My ECMAScript 7 wishlist

2014-06-06 Thread Frankie Bagnardi
Couldn't preventUndeclaredGet() be implemented with proxies?

It actually sounds like an extremely useful feature for development builds
of libraries and applications.  Typos are very very common, and often
difficult to look over while debugging.  On the other hand, it would break
a lot of existing code if you try to pass it as an object to a library;
you'd have to declare every possible value it might check (which
isn't necessarily bad).  Most of the time, it's just an options object, or
an object it'll iterate over the keys of.

Using it on arrays would also reduce off-by-1 errors (though I don't see
them often in JS).




On Fri, Jun 6, 2014 at 7:37 AM, David Bruant bruan...@gmail.com wrote:

  Le 06/06/2014 15:57, Mark S. Miller a écrit :

 By contrast, a Map's state is more like the private instance variable
 state of a closure or a post-ES6 class.

 The capabilities to arbitrarily modify Maps (set/delete on all keys, with
 any values) will be expected by any ES6-compliant code to be globally
 available, so a Map's state cannot reasonably be considered private.
 This differs from the state of a closure where its access is strictly
 moderated by the public API giving access to it and to the fact that this
 API is not provided globally (unlike Map.prototype).


   Object.freeze of a Map should not alter the mutability of this state
 for the same reason it does not alter the state captured by a closure or a
 future class instance.

 I'd argue the Map state is very much like regular objects (for which you
 can't deny [[Set]], [[Delete]], etc.), not closure's state.

 In an ES6 world, denying access to the global Map.prototype.* would break
 legitimate code, so that's not really an option confiners like Caja could
 provide.




 or should an Object.makeImmutable be introduced? (it would be freeze +
 make all internal [[*Data]] objects immutable)


  We do need something like that. But it's a bit tricky. A client of an
 object should not be able to attack it by preemptively deep-freezing it
 against its wishes.

 I don't see the difference with shallow-freezing?
 It's currently not possible to defend against shallow-freezing (it will be
 possible via wrapping in a proxy).



 This can be achieved with Proxy right, or is that too cumbersome?

  Code-readability-wise, wrapping in a proxy is as cumbersome as a call to
 Object.preventUndeclaredGet I guess.

 This sort of concerns are only development-time concerns and I believe
 the runtime shouldn't be bothered with these (I'm aware it already is in
 various web). For instance, the TypeScript compiler is capable today of
 catching this error. Given that we have free, cross-platform and fairly
 easy to use tools, do we need assistance from the runtime?


  Yes. Object.freeze is a runtime production protection mechanism, because
 attacks that are only prevented during development don't matter very much
 ;).

 Just to clarify, I agree that Object.freeze was necessary in ES5 (have we
 had proxies, it might have been harder to justify?), because there was no
 good alternative to protect an object against the parties it was shared
 with.
 But the concern Nicholas raises doesn't seem to have this property.
 Reading a property that doesn't exist doesn't carry a security risk, does
 it? Object.preventUndeclaredGet doesn't really protect against anything
 like ES5 methods did.

 David

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


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


Re: My ECMAScript 7 wishlist

2014-06-06 Thread David Bruant

Le 06/06/2014 17:47, Frankie Bagnardi a écrit :

Couldn't preventUndeclaredGet() be implemented with proxies?
Yes it can. Doing it left as an exercise to the reader... Wait... Don't 
bother, Nicholas did it :-)

http://www.nczonline.net/blog/2014/04/22/creating-defensive-objects-with-es6-proxies/

It actually sounds like an extremely useful feature for development 
builds of libraries and applications.  Typos are very very common, and 
often difficult to look over while debugging.  On the other hand, it 
would break a lot of existing code if you try to pass it as an object 
to a library; you'd have to declare every possible value it might 
check (which isn't necessarily bad).  Most of the time, it's just an 
options object, or an object it'll iterate over the keys of.


Using it on arrays would also reduce off-by-1 errors (though I don't 
see them often in JS).
Ever since I've started using forEach/map/filter/reduce, I haven't had 
an off-by-one error on arrays. Highly recommanded! (I think I've heard 
Crockford making the same recommandation in a recent talk, but I cannot 
find the link)


David






On Fri, Jun 6, 2014 at 7:37 AM, David Bruant bruan...@gmail.com 
mailto:bruan...@gmail.com wrote:


Le 06/06/2014 15:57, Mark S. Miller a écrit :

By contrast, a Map's state is more like the private instance
variable state of a closure or a post-ES6 class.

The capabilities to arbitrarily modify Maps (set/delete on all
keys, with any values) will be expected by any ES6-compliant code
to be globally available, so a Map's state cannot reasonably be
considered private.
This differs from the state of a closure where its access is
strictly moderated by the public API giving access to it and to
the fact that this API is not provided globally (unlike
Map.prototype).



Object.freeze of a Map should not alter the mutability of this
state for the same reason it does not alter the state captured by
a closure or a future class instance.

I'd argue the Map state is very much like regular objects (for
which you can't deny [[Set]], [[Delete]], etc.), not closure's state.

In an ES6 world, denying access to the global Map.prototype.*
would break legitimate code, so that's not really an option
confiners like Caja could provide.





or should an Object.makeImmutable be introduced? (it would be
freeze + make all internal [[*Data]] objects immutable)


We do need something like that. But it's a bit tricky. A client
of an object should not be able to attack it by preemptively
deep-freezing it against its wishes.

I don't see the difference with shallow-freezing?
It's currently not possible to defend against shallow-freezing (it
will be possible via wrapping in a proxy).





This can be achieved with Proxy right, or is that too
cumbersome?

Code-readability-wise, wrapping in a proxy is as cumbersome
as a call to Object.preventUndeclaredGet I guess.

This sort of concerns are only development-time concerns and
I believe the runtime shouldn't be bothered with these (I'm
aware it already is in various web). For instance, the
TypeScript compiler is capable today of catching this error.
Given that we have free, cross-platform and fairly easy to
use tools, do we need assistance from the runtime?


Yes. Object.freeze is a runtime production protection mechanism,
because attacks that are only prevented during development don't
matter very much ;).

Just to clarify, I agree that Object.freeze was necessary in ES5
(have we had proxies, it might have been harder to justify?),
because there was no good alternative to protect an object against
the parties it was shared with.
But the concern Nicholas raises doesn't seem to have this
property. Reading a property that doesn't exist doesn't carry a
security risk, does it? Object.preventUndeclaredGet doesn't really
protect against anything like ES5 methods did.

David

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




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


Re: My ECMAScript 7 wishlist

2014-06-06 Thread Nicholas C. Zakas


On 6/5/2014 4:08 PM, Rick Waldron wrote:


* `Object.deepPreventExtensions()`, `Object.deepSeal()`,
`Object.deepFreeze()` - deep versions of
`Object.preventExtensions()`, et al.


Does deep mean that a Map instance's [[MapData]] is frozen if 
deepFreeze is called on a ? eg. what happens here:


var m = Object.deepFreeze(new Map());
m.set(1, 1);

In your blog it mentions the silent failure in non-strict mode, I 
suspect that would still have to apply to these additions for semantic 
consistency.


I wouldn't expect this to apply to [[MapData]] since those are not 
enumerable own properties of the map instance.


* `Object.preventUndeclaredGet()` - change an object's behavior to
throw an error if you try to read from a property that doesn't
exist (instead of returning `undefine`).


This can be achieved with Proxy right, or is that too cumbersome?


It can be done with Proxy, but that kind of sucks because I always need 
to go through the extra step of creating the Proxy for each object and 
passing around the Proxy instead. To me, this is similar to setting a 
property to be readonly in strict mode, except its writeonly (or rather, 
write-first).


--
___
Nicholas C. Zakas
http://www.nczonline.net

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


Re: My ECMAScript 7 wishlist

2014-06-06 Thread Nicholas C. Zakas


On 6/6/2014 8:38 AM, Mark S. Miller wrote:


But the concern Nicholas raises doesn't seem to have this
property. Reading a property that doesn't exist doesn't carry a
security risk, does it? Object.preventUndeclaredGet doesn't really
protect against anything like ES5 methods did.


That's true, but misses the point I was trying to make. For normal ES 
objects, it is already part of their API contract with their clients 
that the clients can do feature testing to detect the presence or 
absence of a method. The most common way to do such feature testing is 
to get the property and see if it is falsy. (Variations include, 
testing for undefined, testing for undefined or null, and testing if 
its typeof is function.) It's fine if the provider of an abstraction 
does not wish to support this pattern. But it is not ok for one client 
of an object which does support it to prevent that object's other 
clients from successfully using feature detection.


Sorry I was sleeping while most of this conversation was happening. :)

I understand the point about feature detection, it would suck if some 
random code did Object.preventUndeclaredGet() on an object you own and 
were using feature detection on. I still wish for some way to do this 
other than through proxies, but I agree that it would be nice for just 
the object provider to be able to set this behavior.


--
___
Nicholas C. Zakas
http://www.nczonline.net

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


Re: My ECMAScript 7 wishlist

2014-06-06 Thread David Bruant

Le 06/06/2014 18:16, Nicholas C. Zakas a écrit :


On 6/6/2014 8:38 AM, Mark S. Miller wrote:


But the concern Nicholas raises doesn't seem to have this
property. Reading a property that doesn't exist doesn't carry a
security risk, does it? Object.preventUndeclaredGet doesn't
really protect against anything like ES5 methods did.


That's true, but misses the point I was trying to make. For normal ES 
objects, it is already part of their API contract with their clients 
that the clients can do feature testing to detect the presence or 
absence of a method. The most common way to do such feature testing 
is to get the property and see if it is falsy. (Variations include, 
testing for undefined, testing for undefined or null, and testing if 
its typeof is function.) It's fine if the provider of an 
abstraction does not wish to support this pattern. But it is not ok 
for one client of an object which does support it to prevent that 
object's other clients from successfully using feature detection.


Sorry I was sleeping while most of this conversation was happening. :)

I understand the point about feature detection, it would suck if some 
random code did Object.preventUndeclaredGet() on an object you own and 
were using feature detection on. I still wish for some way to do this 
other than through proxies, but I agree that it would be nice for just 
the object provider to be able to set this behavior.

It is possible via an API following the same pattern than revocable proxies:

{object, toggle} = makeUndeclGetThrowObject()
toggle(); // now the object throws when there is a [[Get]] on an 
undef property


Keep the toggle function locally so only trusted parties access it, 
share the object as you wish.

Admittedly more cumbersome than your solution or proxies :-p

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


Re: My ECMAScript 7 wishlist

2014-06-06 Thread Andrea Giammarchi
On Fri, Jun 6, 2014 at 8:38 AM, Mark S. Miller erig...@google.com wrote:

  The most common way to do such feature testing is to get the property and
 see if it is falsy.


this is why for years many of us have been advocating the usage of `'name'
in object` instead of passing through getters ... but I can see the problem
when it comes to retrieve, let's say `requestAnimationFrame`, passing
through all prefixes ...

About that, if I can add one wish for ES7, I really wish that if there's
anything that works with a prefix, an `experimentalPrefix` property is
exposed somewhere so that we can stop guessing which one would work for the
current engine and simplify features detections too.

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


Re: My ECMAScript 7 wishlist

2014-06-06 Thread Brendan Eich

Nicholas C. Zakas wrote:
It can be done with Proxy, but that kind of sucks because I always 
need to go through the extra step of creating the Proxy for each 
object and passing around the Proxy instead. To me, this is similar to 
setting a property to be readonly in strict mode, except its writeonly 
(or rather, write-first).


What about the code I showed, which shows a singleton being spliced high 
on many objects' prototype chains to handle the missing property throw?


js var NoSuchProperty = Proxy({}, {
  has: function(target, name) { return true; },
  get: function(target, name, receiver) {
if (name in Object.prototype) {
  return Reflect.get(Object.prototype, name, receiver);
}
throw new TypeError(name +  is not a defined property);
  }
});
js var obj = Object.create(NoSuchProperty)
js obj.foo = 42
42
js obj.foo
42
js obj.bar
/tmp/p.js:7:4 TypeError: bar is not a defined property

You could avoid Object.create by assigning to a Constructor.prototype, 
or hacking with __proto__, of course.


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


Re: My ECMAScript 7 wishlist

2014-06-06 Thread Brendan Eich
Just FTR, I'll put a ratioanlized ES7 proposal on the agenda for the 
July TC39 meeting, as per


https://twitter.com/BrendanEich/status/475067783282057216

Thanks to Nicholas for the suggestion!

/be

Brendan Eich wrote:

Nicholas C. Zakas wrote:
It can be done with Proxy, but that kind of sucks because I always 
need to go through the extra step of creating the Proxy for each 
object and passing around the Proxy instead. To me, this is similar 
to setting a property to be readonly in strict mode, except its 
writeonly (or rather, write-first).


What about the code I showed, which shows a singleton being spliced 
high on many objects' prototype chains to handle the missing property 
throw?


js var NoSuchProperty = Proxy({}, {
  has: function(target, name) { return true; },
  get: function(target, name, receiver) {
if (name in Object.prototype) {
  return Reflect.get(Object.prototype, name, receiver);
}
throw new TypeError(name +  is not a defined property);
  }
});
js var obj = Object.create(NoSuchProperty)
js obj.foo = 42
42
js obj.foo
42
js obj.bar
/tmp/p.js:7:4 TypeError: bar is not a defined property

You could avoid Object.create by assigning to a Constructor.prototype, 
or hacking with __proto__, of course.


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

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


Re: My ECMAScript 7 wishlist

2014-06-06 Thread Andrea Giammarchi
that `has:()=true` breaks with features detections that are meant to be
less obtrusive than getters ... i.e. `'geolocation' in navigator` or
`'innerHTML' in genericNode` and all others that are not supposed to pass
through a potentially expensive getter to retrieve a feature detection
purpose info.

Long story short that NoSuchProperty is obtrusive in an upside-down way ...
I personally would not use that and would not expect that anywhere
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


My ECMAScript 7 wishlist

2014-06-05 Thread Nicholas C. Zakas
I wrote this blog post about some of the pain points I'm dealing with 
and dreams of how ES7 might be able to address them:


http://www.nczonline.net/blog/2014/06/03/my-ecmascript-7-wishlist/

A short overview in lieu of posting the whole article here:

* `Array.prototype.first()`, `Array.prototype.last()` - return the first 
and last items, respectively.
* `Array.prototype.isEmpty()` - return true when empty (would also be 
nice on strings, maps, etc.).
* `Function.empty` - a standard empty function that can be used when you 
just want an empty function (IMHO, it indicates intent much better than 
other options toda).
* Custom descriptor attributes - David mentioned this likely will never 
happen, which makes me sad. Maybe the decorators proposal solves this 
use case.
* `Object.deepPreventExtensions()`, `Object.deepSeal()`, 
`Object.deepFreeze()` - deep versions of `Object.preventExtensions()`, 
et al.
* `Object.preventUndeclaredGet()` - change an object's behavior to throw 
an error if you try to read from a property that doesn't exist (instead 
of returning `undefine`).
* Lightweight traits - simple syntax sugar for object literals and 
classes to facilitate mixins.


Further rationale and explanation is in the post. The last three, in 
particular, scratch particular itches I currently have.


**Note:** Please don't take these as formal proposals. If any of the 
ideas seems worthwhile, I'm happy to discuss further and/or put together 
an actual proposal.


Thanks.

--
___
Nicholas C. Zakas
http://www.nczonline.net

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


Re: My ECMAScript 7 wishlist

2014-06-05 Thread Rick Waldron
On Thu, Jun 5, 2014 at 6:42 PM, Nicholas C. Zakas 
standa...@nczconsulting.com wrote:

 I wrote this blog post about some of the pain points I'm dealing with and
 dreams of how ES7 might be able to address them:

 http://www.nczonline.net/blog/2014/06/03/my-ecmascript-7-wishlist/

 A short overview in lieu of posting the whole article here:

 * `Array.prototype.first()`, `Array.prototype.last()` - return the first
 and last items, respectively.


Check out Till's response to the previous thread about first and last:
https://mail.mozilla.org/pipermail/es-discuss/2014-May/037158.html


 * `Array.prototype.isEmpty()` - return true when empty (would also be nice
 on strings, maps, etc.).


+1


 * `Function.empty` - a standard empty function that can be used when you
 just want an empty function (IMHO, it indicates intent much better than
 other options toda).


+1


 * Custom descriptor attributes - David mentioned this likely will never
 happen, which makes me sad. Maybe the decorators proposal solves this use
 case.


The Proxy security issue:
http://esdiscuss.org/topic/object-getownpropertydescriptor-can-return-just-about-anything
I had hoped that a black list of writable, configurable, enumerable
properties would suffice:
http://esdiscuss.org/topic/object-getownpropertydescriptor-can-return-just-about-anything#content-14
but I there is a discussion around some form of custom meta properties.


 * `Object.deepPreventExtensions()`, `Object.deepSeal()`,
 `Object.deepFreeze()` - deep versions of `Object.preventExtensions()`, et
 al.


Does deep mean that a Map instance's [[MapData]] is frozen if deepFreeze
is called on a ? eg. what happens here:

var m = Object.deepFreeze(new Map());
m.set(1, 1);

In your blog it mentions the silent failure in non-strict mode, I suspect
that would still have to apply to these additions for semantic consistency.



 * `Object.preventUndeclaredGet()` - change an object's behavior to throw
 an error if you try to read from a property that doesn't exist (instead of
 returning `undefine`).


This can be achieved with Proxy right, or is that too cumbersome?


 * Lightweight traits - simple syntax sugar for object literals and classes
 to facilitate mixins.


+ 1



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


Re: My ECMAScript 7 wishlist

2014-06-05 Thread Axel Rauschmayer
 * `Function.empty` - a standard empty function that can be used when you just 
 want an empty function (IMHO, it indicates intent much better than other 
 options toda).

Ironically, that’s what Function.prototype is. But using that object in that 
capacity is beyond confusing. I’d prefer a different name such as “noop” or 
“doNothing”; “empty” doesn’t feel right in the context of something executable.

Also, I don’t find using an empty arrow function too bad (to me, it looks quite 
intention-revealing):

```js
someAsyncMethod(() = {});
```

-- 
Dr. Axel Rauschmayer
a...@rauschma.de
rauschma.de



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


Re: My ECMAScript 7 wishlist

2014-06-05 Thread Brendan Eich

Rick Waldron wrote:


* `Object.preventUndeclaredGet()` - change an object's behavior to
throw an error if you try to read from a property that doesn't
exist (instead of returning `undefine`).


This can be achieved with Proxy right, or is that too cumbersome?


js var NoSuchProperty = Proxy({}, {
  has: function(target, name) { return true; },
  get: function(target, name, receiver) {
if (name in Object.prototype) {
  return Object.prototype[name];
}
throw new TypeError(name +  is not a defined property);
  }
});
js var obj = Object.create(NoSuchProperty)
js obj.foo = 42
42
js obj.foo
42
js obj.bar
/tmp/p.js:7:4 TypeError: bar is not a defined property

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


Re: My ECMAScript 7 wishlist

2014-06-05 Thread Allen Wirfs-Brock

On Jun 5, 2014, at 5:52 PM, Brendan Eich bren...@mozilla.org wrote:

 Rick Waldron wrote:
 
 * `Object.preventUndeclaredGet()` - change an object's behavior to throw an 
 error if you try to read from a property that doesn't exist (instead of 
 returning `undefine`).
 
 This can be achieved with Proxy right, or is that too cumbersome? 
 
 js var NoSuchProperty = Proxy({}, {
   has: function(target, name) { return true; },
   get: function(target, name, receiver) {
 if (name in Object.prototype) {
   return Object.prototype[name];
 }
 throw new TypeError(name +  is not a defined property);
   }

need to make sure accessor methods use the right this value:

get: function (target, name, receiver) {
   if (name in Object.prototype) return Reflect.get(Object.prototype, 
name, receiver);
   throw new TypeError(name + “ is not a defined property”);
 }
 });

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


Re: My ECMAScript 7 wishlist

2014-06-05 Thread Brendan Eich
LOL - as if O.p has getters!

Thanks, this is more general in case of insanity.

/be

 On Jun 5, 2014, at 6:09 PM, Allen Wirfs-Brock al...@wirfs-brock.com wrote:
 
 
 On Jun 5, 2014, at 5:52 PM, Brendan Eich bren...@mozilla.org wrote:
 
 Rick Waldron wrote:
 
 * `Object.preventUndeclaredGet()` - change an object's behavior to throw 
 an error if you try to read from a property that doesn't exist (instead of 
 returning `undefine`).
 
 This can be achieved with Proxy right, or is that too cumbersome?
 
 js var NoSuchProperty = Proxy({}, {
   has: function(target, name) { return true; },
   get: function(target, name, receiver) {
 if (name in Object.prototype) {
   return Object.prototype[name];
 }
 throw new TypeError(name +  is not a defined property);
   }
 
 need to make sure accessor methods use the right this value:
 
 get: function (target, name, receiver) {
if (name in Object.prototype) return Reflect.get(Object.prototype, 
 name, receiver);
throw new TypeError(name + “ is not a defined property”);
  }
 });
 
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: My ECMAScript 7 wishlist

2014-06-05 Thread Allen Wirfs-Brock

On Jun 5, 2014, at 6:25 PM, Brendan Eich bren...@mozilla.org wrote:

 LOL - as if O.p has getters!
 
 Thanks, this is more general in case of insanity.

It probably always a good idea to use Reflect.* calls inside of proxy handlers. 
 I’m seen variants of this mistake in many handlers snippets that are floating 
around.  Need to encourage best practices.

Allen


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