On Jul 9, 2011, at 1:43 PM, Brendan Eich wrote:
> 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.
>
> Do we want users extending Array or Function? Same problem as applies to
> object. In Edition N+1 we then collide. I don't see a difference in kind here.
No, but the example we are setting is that if you are hanging such predicates
off of constructors they should be constructors related to what you are testing
rather than Object.
>
>
>> Another consider is whether such classification schemes should use methods
>> or data properties. An instance side, isFoo() method to be useful generally
>> will also require the addition of an isFoo() method to Object.prototype
>> while a instance side-data property can be tested without augmenting
>> Object.prototype (({}.isFoo) is a falsey value). Also most user code
>> classification schemes will require some sort of instance-side tagging or
>> testing to actually determine whether the instance is in the category.
>>
>> For those reasons, I think the best classification scheme is usually via an
>> instance-side public data property with a truthy value.
>
> I don't agree, because detecting truthy valued properties from host objects
> (proxies) can have effects. Calling a well-known predicate function that has
> no side effects is better.
That may be true for host objects/proxies. But in general for plain user
defined objects such a predicate function is going to have to inspect the
instance for some identifying characteristic (assuming it is a situation where
instance of isn't adequate or desirable). That characteristic is presumably
going to manifest some sort of trademark property on the instance. If you are
considered about spoofing I can see why you might use a well known predicate
that depends upon a private name based trade mark. However, if that isn't your
concern (and my perspective is that in most cases it shouldn't be) you might as
well use a public trademark property on instances in which case a direct test
for that property is probably all you need.
However, I agree that best practice would be for such property to have no
access side-effects, regardless of how they were are implemented.
>
>
>> But there are some exceptions. For the legacy built-ins such as Array is
>> less risky from compatibility perspective to add properties to the
>> constructor than to the prototype. However, for new built-in this isn't an
>> issue. Another consider is meta layering: meta-layer functions shouldn't be
>> exposed on application layer objects. Proxy.isProxy is a good example.
>> Proxy instances operate as application objects in the application layer.
>> The public face of application objects shouldn't be polluted with a
>> meta-layer method such as isProxy.
>
> Do we want intercession by proxies for any of these isFoo predicates?
In general yes. Let's say a new kind of Crazy DOM node interfaces defines that
it has a isCrazyNode property and also has semantics that requires the use of a
Proxy to natively implement it in JS. In that case isCrazyNode needs to be
implemented via the Proxy.
On the other hand, we don't want random objects to start exposing isProxy
properties just because a Proxy was used to implement it. That would be
unnecessarily exposing implementation details. I fall back o my standard test,
can Proxies be used to implement ES Array instances. If such instances
implemented via Proxies had a visible isProxy property they would not be a
accurate implemented on the ES spec. for array instances.
>
>
>>> Why not Function.isGenerator? Because the prototype method is more usable
>>> when you have a function in hand and you want to know whether it's a
>>> generator. If you have any value x, you'll need (typeof x === 'object' &&
>>> 'isGenerator' in x) guarding the x.isGenerator() call, but we judged that
>>> as the less common use-case.
>>
>> Why not just make it a boolean-valued data property?
>
> See above, and also isArray and other isFoo predicates (isNaN) realized via
> functions, not data properties.
OK, if you have a distinct function that isn't a method instance. However, in
general you have to hang that function off of come object (such as the
constructor). That means that a test site must have access (probably lexical)
to the container of the predicate and must know the name of the predicate. The
contain is probably accessed via a module import and if it is a constructor you
get access to capabilities (such as creating instances) that go far beyond
simply category testing. That violates the principle of least privilege.
I think self identifying objects have much better modularity. All you need to
know is the name of the categorization property and that should be part of the
instance interface that you are already depending upon. If you do it that way
there is no need to import a constructor or other container of the predicate
and expose additional capabilities that might be available from those. BTW, my
concern here isn't security based. It is that minimizing module dependencies
give you more maintainable code.
>
>
>>> Could be we were wrong, or that being consistent even in the
>>> hobgoblin/foolish sense is better. But Object.isGenerator crowds poor
>>> Object more.
>>>
>>> Notice how there's no need for Function.isFunction or Object.isFunction,
>>> due to typeof (function(){}) === 'function'. That's another dawn-of-time
>>> distinction that does not fit the primitiive types vs. object
>>> classification use-case I mentioned in the last message -- testing whether
>>> x is callable via typeof x === 'function', at least for native if not host
>>> objects, is the use-case here.
>>
>> But this is a special case that does not extrapolate to other situations.
>
> Agreed, although we've said we'll consider typeof-result extensions in the
> future, e.g., for user-defined value types.
>
>
>>> Some of these questions are at this point more about aesthetics and
>>> Principles than about usability. And we have historic messiness in how
>>> things have grown.
>> In a utilitarian language like JS, usability and aesthetic considerations
>> should be closely linked and consistency is a significant usability factor.
>> . Principles are a way to get consistent application of such aesthetics .
>
> It's hard to disagree, but that doesn't settle disagreements, e.g., on data
> properties that are true-valued or missing, so undefined-falsy, vs. pure
> predicate functions.
My argument for self-identify objects rather than independent predicates is
above.
If you buy that self-identify is better, then the question becomes data
property or instance methods. To me that comes down to, if someone is going to
have to code if (typeof obj.isFoo == 'function' && obj.isFoo()) ... why not
just say if (obj.isFoo)...
A major source of monkey patch in large Smalltalk applications was people
adding isFoo ^false methods to Object so they could test arbitrary objects
for Fooness. I'm assume that as people start building complex JS applications
using rich inheritance based duck typed "class" libraries they are going to
find the need to do the same sort of classification testing. Data property
testing is a way to accomplish this without the monkey patching.
Allen
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss