using Private name objects for declarative property definition.

Allen Wirfs-Brock allen at wirfs-brock.com
Mon Jul 11 19:31:35 PDT 2011


On Jul 11, 2011, at 6:14 PM, Brendan Eich wrote:

> On Jul 11, 2011, at 5:29 PM, Allen Wirfs-Brock wrote:
> 
>> However, for pure JS classification you want them to be duck-type extensible. It is easy to add a new implementation for some category if the category test uses an instance property classification property (whether method or data property) and perhaps with some monkey patching.   But a single global predicate can't be post facto extended to recognize new implementations of the category unless it was built with some internal extension mechanism (and any any such mechanism is likely to depend upon some per instance property, so that just loops us back to the same solution).
> 
> Why switch topics to pure JS classification, though? There are two different use-cases here.

Well, I thought we were trying to find a pattern that was applicable to both:

On Jul 9, 2011, at 11:19 AM, Allen Wirfs-Brock wrote:

> A consideration here is that whatever conventions we follow sets a precedent for user written code. I don't think we want to encourage the addition of such classification functions to Object or Object.prototype.  So from that perspective Array.isArray, Function.isGenerator, and Proxy.isProxy are better exemplars than Object.isArray, etc.


 Maybe we weren't as user written code normally does define these sorts of implementation classifications.  However, the fact it took this long for us (well, at least me) to see that probably is a good indication that this distinction isn't always an obvious one. 

> 
>>>> However, methods are less desirable for class-like categorization because they require an existence predicated call (f.isFoo && f.isFoo()) which potentially leads to monkey patching Object.prototype (Object.prototype.isFoo = function(){return false}).  A truthy data property is a plausable alternative that avoids the need for monkey patching, but it doesn't work for value tests.
>>> 
>>> Only if you know you have an object. If the predicate you need has signature "any -> boolean" then you want a function.
>> 
>> All values except for null and undefined are automatically coerced to objects for property access.
> 
> Yes, null and undefined "count" -- especially since with an unknown value you are more likely to have undefined than 42 or "foo". Also, nasty host objects.
> 
> I don't think "close enough, ignore null and undefined" cuts it.
> 
> 
>> If a value is expected to possibly be null or undefined then that probably represents a separate condition and should have a separate test.
> 
> Why?

When used as an explicit marker then there is probably explicit logic to deal with whatever the marker represents.  The test for that condition can precede any other classification test.

If  they are being used intentionally then as such a marker then property accessing dereferencing them is probably an unintended error situation.

> 
> One can write any -> boolean functions. Many built-in operators and functions take any type input argument, not only non-null object arguments.

Regardless of whether or not that was a wise design choice, it is precedent that we do need to consider. 
> 
> A restriction against null and undefined is arbitrary and it taxes all programmers who have to (remember to) write the extra test, instead of taxing the implementation to provide the predicate once for all.
> 
> 
>> If null/undefined is not an anticipate value then an exception on the property access is probably a fine dynamic error check.
> 
> Not for Array.isArray or the other built-ins we're discussing.
Yes, but since we seem to be circling in predicate functions for those tests it's not an issue for them.

> 
> We shouldn't make arbitrary judgments against certain use-cases. Sometimes you know you have an object (or even a function), and a "narrower" input type for a predicate will do. Other times, you need the widest (any -> boolean) predicate. And the latter can work in the former cases without trouble. So why insist on object.method() with throw on null or undefined?


Well, this may be a style point that we can't agree on.  I do think, that undefined and null are special cases that probably need to be explicitly dealt within when their use is intentional.  

> 
> 
>>>> If a value tests can be recast as a class-like categorization then the data property approach works for it.
>>> 
>>> Right, but you can't "recast" for any type of value without writing a prior typeof conjunct. Or did you mean something else by "recast"?
>> 
>> No, I don't mean a dynamic type cast.  I meant something like giving generator functions a distinct prototype so the isGenerator: true could be factored out of the individual instances. 
> 
> That does not handle the nominal type test you agree is the purpose of isGenerator, so I don't know why you're citing this use-case for the other, is-a-loose-duck-type case.

Because I got confused about what problem we were trying to solve.  Also, like I said above, the distinction between the two use cases may not be so obvious. 

> 
> 
>>>> Using an alternative prototype for all values in a "subclass" (eg all generators) seems like a technique that might be plausible in situations like this.  It is essentially just a way to factor out of each generator the storage of the true value for the isGenerator property.  It doesn't require the exposure of a separate Generator constructor. 
>>> 
>>> I think this misses the mark. Both Array.isArray in ES5 and Function.isGenerator in ES.next are testing nominal type tag. They are not testing some ad-hoc boolean "tag" that is not reliable and that can be forged.
>> 
>> I agree.  But we are trying extrapolate to a pattern that is applicable for any application defined classification scheme.
> 
> No, or at least: I'm not. Rather, I'm trying to find out whether there is one pattern, or two. I see at least one, the nominal tag test. That needs attention.
> 
> We can get to the other one, the loose foo.isDuck boolean data property or undefined falsy-value test, only if we really need to. I think you've made a good case for its extensible nature. But I'd rather leave it for JS users and library authors. And isGenerator has nothing to do with it.

Yes, I agree.  Except for the concern that users in duckish situations will follow the nominal tag test pattern we establish because that is the only examplar they have. 
> 
> 
>> Those typically won't be deep nominal types with implementation dependencies.   It may simply be that isGenerator (and perhaps isArray) just isn't a good exemplar for the more general situation.
> 
> Whew! That's what I've been getting at.
> 
> But per my above words, I'd like to go further in seeking clarity about what *not* to do, as well as what to do, and what patterns to keep in mind for later (so I'm not complaining about taking the time to diagram the use-cases and solutions a bit). I simply don't see why we need the isDuck method pattern for any built-ins in ES5 or proposed for Hamony. And here I include elaboration of generators' prototype chains.

Perhaps not, as we have said we want to steer away from adding complex libraries to the core language. However, some of the discussion today about extending Array.prototype function feels like it might lead into a space that might need isDuck.  Same for the I18N library work.

> 
>>>> An independent classification function (perhaps hung from a constructor) may be a good solution when value classification will generally be done in situations where the "class" of the value is not predetermined.
>>> 
>>> Agreed.
>> 
>> and the classification doesn't need to be extensible to new implementations.
> 
> Right, that's a good point. The isDuck scheme is extensible -- to a fault! :-P
> 
> 
>>>> A truthy isFoo data property works will for class-like categorization as long as all values that share the same prototype are considered members of the same category.
>>> 
>>> Disagree for the use-cases you applied this to. ES5 mandates a [[Class]] check for Array.isArray, and the impetus there was cross-frame Array classification based on nominal really-truly-built-in-Array type tag.
>>> 
>>> Ditto for any isGenerator worth its name, that is, to the extent that the use-case for isGenerator does not simply want to test "is it an iterator factory", which could be a structural or duck-type test.
>> 
>> Agreed, these are both cases where the category isn't user extensible.  However, I think my statement holds for class-like categorization that are extensible.
> 
> Do we have any examples of those in the spec., or contemplated for ES.next?

See http://wiki.ecmascript.org/doku.php?id=strawman:es5_internal_nominal_typing #8: 
 In JSON.stringify, use a isJSONArray property to control output in array literal syntax and eliminate corresponding [[Class]] check.

Allen




-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20110711/b8a11b80/attachment-0001.html>


More information about the es-discuss mailing list