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