Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

instanceof? #4

Closed
ljharb opened this issue May 21, 2015 · 25 comments
Closed

instanceof? #4

ljharb opened this issue May 21, 2015 · 25 comments

Comments

@ljharb
Copy link
Member

ljharb commented May 21, 2015

Now that objects are returned from Symbol(), could we make Symbol() instanceof Symbol be false, but Object(Symbol()) instanceof Symbol be true? It'd require wrapping Object itself, and some prototype chain reorganization so that {} instanceof Object remained true, but it should be doable. You maybe could even make Symbol() instanceof Object be false, but that's probably harder.

@WebReflection
Copy link
Member

wrapping the Object ... doesn't seem to be a very good idea to me, not sure for which concrete gain. I will think about it.

P.S. right now Symbol() instanceof Symbol already returns false

@ljharb
Copy link
Member Author

ljharb commented May 21, 2015

True enough - added that check in ljharb/object.assign@59b94e0 but I'll wait on the Object() check :-)

@WebReflection
Copy link
Member

uhm ... it might be a long wait ... 'cause I want to see how this ends up:
zloirock/core-js#16

they have instanceof Symbol returning true, but if they'll wrap the Object I might do the same.

I just don't fancy too much the idea of wrapping the Object 'cause if I do that, everyone else might have similar thoughts resulting in a proper mess everyone is responsible for ...

I should change the Object.prototype.constructor too and be sure there's no way to retrieve it in any other way ... I honestly rather avoid this approach the more I think about it.

@ljharb
Copy link
Member Author

ljharb commented May 21, 2015

I'm fine leaving this open as long as necessary :-)

The way es6-shim wraps RegExp, it's bulletproof (as far as I know) and also could be wrapped multiple times with no ill effects. I don't see why Object couldn't work the same way.

@WebReflection
Copy link
Member

can I have a use case for this request, beside the aim to the perfect shim that we know already is not possible?

@zloirock
Copy link

Wrapper for Object isn't bulletproof - by ES6 many other methods should convert primitives to objects. For example, Object.getPrototypeOf(Symbol()) === Symbol.prototype should be true.

@WebReflection
Copy link
Member

actually, I've got this result in here ...

screenshot from 2015-05-21 18-08-19

@ljharb
Copy link
Member Author

ljharb commented May 21, 2015

That's a spec error in Chrome - Object.getPrototypeOf should convert to object in step 1 of https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.getprototypeof, which is new in ES6.

@ljharb
Copy link
Member Author

ljharb commented May 21, 2015

The primary use case is to eliminate as many caveats as possible, so the list is both exhaustive and small. If it ends up being impossible, so be it, but I still believe it is possible :-)

@WebReflection
Copy link
Member

sorry but I've asked for a use case ... I see most of the things I am putting in completely pointless for the real-world, and since it's clear this is a sham I wonder why should I pollute and wrap the global Object for something useless.

In order to retrieve Symbols you need special methods, accoridngly what is the point to have that Object(Symbol()) instanceof Symbol behavior?

What is the use case for having it, beside spec compliance for a thing that is not compliant anyway?

@ljharb
Copy link
Member Author

ljharb commented May 21, 2015

Object(foo) is a universal mechanism of ensuring that objects remain objects, and primitives become boxed forms of the primitive. isObject(foo) ? Object(foo) === foo : Object(foo) !== foo (where function isObject(x) { return x !== null && (typeof x === 'object' || typeof x === 'function'); }) is a universal truth in JS.

Any type-checking library, or polymorphic function, which needs to check its arguments may use this approach - many of my shims do.

I'm not obsessively attached to instanceof behavior, since it's long since been unreliable in JS, but var sym = Symbol(); Object(sym) !== sym is something that I feel very strongly must be true. I'll be happy to update the object.assign symbol test to use that instead of instanceof if that seems more sensible.

@WebReflection
Copy link
Member

I've tried already twice to wrap the global Object resulting in any sort of problems in every devce I could test ... so to me it's not sensible to wrap the global Object, it's a thing I haven't even thought about since those times where wrapping global Array was giving you access to defined properties in order to hack security here and there ... I don't know if I'd personally would ever trust a library that swaps natives ... that being said ... Symbol are a different beast than regular ES5 obejcts and patterns.

I don't think anyone would ever pass symbols around just for fun because these cannot be used as objects.

I'd arguably say that typeof foo === 'object' && foo instanceof foo.constructor or typeof foo === 'object' && foo instanceof Foo are equivalently valid checks that do not need the Object wrap with potential pointless primitive wrap creation so ... again ... since you cannot reach Symbols unless:

  1. you hold the value 'cause you created it, you know it's a Symbol
  2. you are using Object.getOwnPropertySymbols(obj) and you won't check those values 'cause you know those are Symbols
  3. since typeof cannot be symbol you might want to retrieve all own properties and symbols and do the typeof prop === 'string' to distinguish

can you please think about a real-world use case that would make me think it's a good idea to wrap native Object contrcutor, beside a common practice that I believe has nothing to do with Symbols 'casue symbols aren't something you pass around without knowing what you are doing?

Sorry for being difficult but I hate messing up natives, I feel already guilty enough here with all the hacks I've created already ...

@ljharb
Copy link
Member Author

ljharb commented May 21, 2015

There's tons of use cases for passing around Symbols and not using them as object keys at all - I'd use them as signal values/semaphores, as constants (better than strings), as placeholders, things like that.

It's fine if you aren't willing to do it, or if it turns out not to be practical, but I still think it's important to bring it up, and attempt it.

@WebReflection
Copy link
Member

I'd use them as signal values/semaphores

meaning you know these are Symbols .. you don't accept/use random signals you are not aware of, right?

as constants (better than strings)

again, you need to know which constant you are referencing

In both cases you don't/won't need the Object(whatConstantIsThis) check because that won't tell you anything useful, unless I am misunderstanding your use case.

If I search typeof === 'symbol' in the entire github I have mostly transpilers related code and checks against typeof Symbol === 'function' which is all developers seem to need right now.

Accordingly, I'd like to see a real-world code where the check Object(obj) instanceof Symbol is used these days ... can you please provide that?

@ljharb
Copy link
Member Author

ljharb commented May 21, 2015

meaning, the code testing that it's the semaphore, and not something else, needs to be able to concretely determine that it's a Symbol, and not anything else.

I do not believe Object(sym) instanceof Symbol exists anywhere - because there's no need for it when typeof sym === 'symbol', or when you use this approach. However, if I'm going to begin writing Symbol code that accepts polyfilled Symbols, I want as many guarantees as I can get since the invariants in the linked code won't be available.

@WebReflection
Copy link
Member

you cannot guard against sham ... if you want to deal with real Symbol you just do typeof obj === "symbol" but you leave the rest of the world that does not include third parts libraries beside a couple of polyfills to use Object.assign which should NOT fix Symbols ... I hope we don't have to start again this discussion

@WebReflection
Copy link
Member

however, if you want to create a "loosey" isSymbol function that trust any Symbol sham the check is straight forward:

function isSymbol(o) {
  return typeof o === "symbol" || (
    typeof o === "object" &&
    o in Object.prototype &&
    o.constructor === Symbol &&
    !(o instanceof Symbol)
  );
}

There is no possible other way to polyfill them in ES5 so that would be a good way without going too dirty ... then if somebody wants to play bad games in there, you already have a problem: you have bad libraries in your core, get rid of them ... right ? :D

@WebReflection
Copy link
Member

actually updated the check, so it's more duck-type centric ;-)

@ljharb
Copy link
Member Author

ljharb commented May 21, 2015

Right, this is what I'm saying - I'm saying that if I want to start making my code not depend on native Symbols, I need other checks that I know your sham (or another reputable one) will provide.

The o in Object.prototype part in your isSymbol check is the part I don't like - I understand that's how the Symbol shims work, but I wouldn't want any code to be coupled to that assumption.

@WebReflection
Copy link
Member

btw, I'm going to sleep now ... I'll leave this bug open waiting to see what happens around ... if these are must have requirements for real-world needs I'll find a way to sqeeze changes in.

Or maybe I'll wake up tomorrow and push all the changes ... who knows, right now I'm using Symbols for a side project and these works great. I understand also concerns of best possible poly ever to filer ... but again I'm not concerned about other polyfills for symbols and I always know what code runs in my projects. A dirty approach, a dirty library, that wants to hack Symbol shams, won't make a minute live in any production (and shouldn't, so not a real problem)

@WebReflection
Copy link
Member

I wouldn't want any code to be coupled to that assumption.

so drop that line and trust that if a typeof variable is an object and its constructor is Symbol and its not an instanceof its own constructor then, by specs, that's a symbol (beside the typeof object, but there's nothing we can do here, it's already good it's not typeof string)

Even thenables are that easy to assume ;-)

@ljharb
Copy link
Member Author

ljharb commented May 22, 2015

I don't currently have Object(Symbol()) instanceof Symbol anywhere yet. If you're not convinced to add it, I simply won't add that test.

@WebReflection
Copy link
Member

OK, sorry I'm late here for an answer. But reading recent update on redefining Promise and the fact it's consider future hostile, I think I won't overwrite the global Object in here so I'll close this as won't fix.

jshint/jshint#1747 (comment)

Apologies for any inconvenience.

@ljharb
Copy link
Member Author

ljharb commented Jun 6, 2015

That comment thread applies to replacing the global Promise with a non-standard Promise implementation - that's not what you'd be doing here. Nobody on TC39 (afaik) considers the es6-shim's overriding of RegExp future-hostile, since it brings it into spec compliance.

@WebReflection
Copy link
Member

I think is generally considered a future hostile practice to overwrite any global. I don't want to do that specially with Object and I won't do that because there are more caveats and possible x-platforms problems than benefits.

Until I'll see the usage of Object(sym) instanceof Symbol in the wild I won't fix this so (I hope) it's OK to keep it closed for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants