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

Reply via email to