Closed Jamesernator closed 7 years ago
I'm confused - all of these things are Function instances, typeof function
, and have a [[Call]]
internal slot. Why would you expect Builtin.typeof
to give you a different result than typeof
here?
(specifically, generator functions and async functions are all instanceof Function
)
I just feel it's a bit weird that "function"
is essentially the brand of instances of Function
even though any exotic could in theory have a [[Call]]
property.
Given that the point of adding Builtin.typeof
is mostly to check constructors cross-realm it doesn't make sense to me that the function would return anything but the name of the constructor used to create the object (and in the case of primitives these have no constructor, so they use typeof
).
It just seems silly to me that this would have a mix of typeof/constructor names for strictly object types:
function cloneToRealm(value) {
// Yes I know some of these are essentially impossible
switch (`Builtin.typeof(value)`) {
case 'Uint8Array':
..
...
case 'GeneratorFunction':
case 'function':
// Not a primitive yet looks like it's one
case 'object':
// Same thing with object
case 'number':
case 'symbol':
...
// primitives are obvious and distinct as they don't use
// the CapWords naming scheme
return value
}
// or this just seems weirdly inconsistent:
// in realm
const isFunction = func instanceof Function
const isMap = map instanceof Map
// vs cross-realm
const isFunction = Builtin.typeof(func) === 'function'
const isMap = Builtin.typeof(map) === 'Map'
That's why I also suggested it should just be called Builtin.type
instead of Builtin.typeof
.
Any exotic with [[Call]] is supposed to be typeof function.
Closing this. The behavior as currently written is as it should be
My point was the opposite way around, it's that a typeof x === 'function'
does not imply that x
was constructed from Function
which is why I think Function[Symbol.builtin]
should return "Function"
not 'function'
.
e.g.:
const f = _ => {}
Object.setPrototypeOf(f, {})
typeof f === 'function' // true
Builtin.typeof(f) === 'function' // false, seems weirdly inconsistent
// why bother using the typeof
// values at all if it isn't even
// consistent with typeof
Similarly for object:
typeof {} === 'object' // true
typeof Object.create(null) === 'object' // true
Builtin.typeof({}) === 'object' // true
Builtin.typeof(Object.create(null)) // false, seems weirdly inconsistent again
It'd make a lot more sense to me if both of those instead were checking for the constructor name e.g.:
Builtin.type({}) === "Object" // true, this is the name of the builtin
// that constructed the object
Builtin.type(_ => {}) === "Function" // true
const f = _ => {}
Object.setPrototypeOf(f, {}) // no longer inherits from Function so
Builtin.type(f) === 'Function' // it isn't a surprise this is false
typeof f === 'function' // whereas this is still true because it remains
// [[Call]]-able
If the typeof
route is going to be taken, I'd at least like to see some justification as to why Builtin.typeof
/typeof
aren't consistent yet use the names to mean different things (typeof
using "function" to mean [[Call]]-able, vs Builtin.typeof
using "function" to mean instanceof (in a cross-realm way) of Function).
Function.prototype[Symbol.builtin].call(f) === 'function'
would still be true, however.
I think it makes more sense for it to be
"Function"
, the reason for this is that the definition oftypeof
for"function"
is essentially just any object with a[[Call]]
internal property.This is a bit confusing when
AsyncFunction
,GeneratorFunction
(and eventuallyAsyncGeneratorFunction
) all also have typeof"function"
, it seems a bit odd to have this more general typeof value to mean justFunction
instances.I feel the same applies to
object
/Object
as well for similar reasons.I'd rather see the method called
Builtin.type
and have it by default return the constructor name for object types only using the lower case form for primitive types.