On Jul 11, 2011, at 12:40 PM, Allen Wirfs-Brock wrote:

> isGenerator is essentially a value test rather than class-like 
> categorization.  Methods work well for this because a method can dynamically 
> inspect the value being tested in order to make the determination.

I'm not so sure about this now. I was just reviewing with Dave how the design 
evolved. We had Function.isGenerator, analogous to Array.isArray. For taskjs, 
Dave had thought he had a use-case where the code has a function and wants to 
know whether it's a generator. It turned out (IIUC) that what he really wanted 
(this will warm your heart) was simply the duck-type "does it implement the 
iterator protocol" test.

On the other hand, code that wants to ask "is this *value* a generator?" may 
not have a-priori knowledge that the value is a function, so a class method 
such as Function.isGenerator wins.

Indeed Array.isArray, apart from being named as if it were a class method just 
to avoid polluting the global (or some other) object, is a predicate function 
-- not  a method. You can't know that you have an Array instance, never mind an 
object-type (typeof sense) value, all the time. If you don't know whether x is 
an array or even an object as opposed to a primitive, just call 
Array.isArray(x).

This strongly suggests to me that we want predicate functions. For the "@name" 
built-in module, isName is one such. There's no need to stick that into a 
"class object" just to avoid name pollution, since the module lets the importer 
name the import.

To rehash a subtle point again: our Function.prototype.isGenerator method is 
particular nasty if a user knows Array.isArray and expects 
Function.isGenerator(x) to test whether x is a generator (or any non-generator, 
whether function or not) value. That expression actually evaluates equivalently 
to Function.prototype.isGenerator.call(Function, x), and x is ignored -- and 
Function is of course not a generator.

So I think we took the wrong door here. Function.isGenerator by analogy to 
Array.isGenerator, or an isGenerator export from "@iter" (equivalent 
semantically), is the best way.


> 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.


> 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"?


> 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.


> We are trying to generalize to a pattern to apply to all (or at least most 
> isFoo) situations.  Here is what we seem to have observed so far:
> 
> A isFoo method works well for value classification for situations where you 
> will generally  already know the "class" of the value.

Agreed.


> A 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.


> 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.

/be
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to