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




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

Reply via email to