Proposal: new Symbol(obj)
You can use a WeakMap to build your own object-selected Symbol factory:
let known = new WeakMap;
function ObjSymFactory(obj) {
//handle obj === undefined however you want
let sym = known.get(obj);
if (!sym) {
sym = new Symbol;
known.set(obj,sym);
}
return sym;
}
Good point, that's definitely a usable solution (also a better representation of what I was attempting to describe).
I'd still be interested in a less-verbose/more-efficient approach using the Symbol constructor, but it may not be a common enough scenario to justify it when a workaround does exist.
I would welcome (with fanfare and parades) a new Symbol(obj) that worked for strings and integers. Such is not possible using the WeakMap shim (you'd have to detect the type of the value and have multiple dictionaries, or something, and you'd leak the symbols forever...)
Of course, what that means is I'm asking for weakly cached symbols with referential identity, which means it would allow detecting garbage collections, so this is probably around the point where people chime in and say it's not possible. Oh well. :(
My expectation would be that...
(a === b) === (new Symbol(a) === new Symbol(b))
I.e., new Symbol(a) === new Symbol(b)
iff a === b
. This satisfies the
strings/integers scenario, but, of course, fails your WeakMap garbage
collection semantics. You need WeakSymbolMaps (+ this proposal) :)
On 12 July 2013 22:29, Jeremy Martin <jmar777 at gmail.com> wrote:
My expectation would be that...
(a === b) === (new Symbol(a) === new Symbol(b))
Nit: you probably either mean
(a === b) >= (new Symbol(a) === new Symbol(b))
or
(Object.is(a, b)) === (new Symbol(a) === new Symbol(b))
In any case, I'd also say that weak maps are good enough for your use case.
(a === b) >= (new Symbol(a) === new Symbol(b))
Not sure I follow... so, I either I don't agree or I don't understand :). I'm having to dig deep to remember my math vocab here, but I think it may be most correct to say that the Symbol constructor, when passed an argument, should be injective. That is,
- let F = new Symbol
- if a = b, then F(a) = F(b)
- if a != b, then F(a) != F(b)
In any case, I'd also say that weak maps are good enough for your use case.
In some (most?) cases, but not all. There's already a consensus that the garbage collection semantics of WeakMaps aren't always appropriate 2. By parameterizing the Symbol constructor, developers can create custom map/set types without the overhead of a "Symbol Factory" (as previously suggested by Allen). I believe this would be a useful building block for interesting and innovative custom types.
On 15 July 2013 15:49, Jeremy Martin <jmar777 at gmail.com> wrote:
Not sure I follow... so, I either I don't agree or I don't understand :). I'm having to dig deep to remember my math vocab here, but I think it may be most correct to say that the Symbol constructor, when passed an argument, should be injective [1].
I agree, but the problem is that JavaScript's ===
is not an
equivalence relation, due to the dreaded NaN !== NaN
that IEEE
invented in some delirium. So you cannot define injectivity based on
it. You merely get an implication for the above, which is what the >=
was supposed to encode. Object.is
OTOH implements a proper equivalence relation, i.e. a "=" in the mathematical sense. It only differs from ===
by having a sane semantics for NaN
.
But as I said, I was merely picking a nit.
On Mon, Jul 15, 2013 at 7:03 AM, Andreas Rossberg <rossberg at google.com>wrote:
It only differs from
===
by having a sane semantics forNaN
.
And a tighter equivalence for -0 vs 0
so, I either I don't agree or I don't understand
It was the latter - I understand and agree now :)
On Jul 15, 2013, at 6:49 AM, Jeremy Martin wrote:
In some (most?) cases, but not all. There's already a consensus that the garbage collection semantics of WeakMaps aren't always appropriate 2. By parameterizing the Symbol constructor, developers can create custom map/set types without the overhead of a "Symbol Factory" (as previously suggested by Allen). I believe this would be a useful building block for interesting and innovative custom types.
An implementation of your proposal is going to have to have to internally use some wort of weak-keyed table, in practice an implementation would probably use the same GC mechanisms that are there to support WeakMap. So, I doubt there would be much performance difference between a built-in and a roll-your-own implementation.
The builtin could have weak values (i.e. Symbol instances expire when no longer referenced by JS) instead of weak keys, which is not something we can currently express in JS. This would also make it possible to use strings/integers/floats as Symbol keys without leaking those Symbol instances forever. This is not something we can express in JS either.
Both of these behaviors would not, as I understand it, be directly observable since keeping an old Symbol instance around (to compare with) would prevent the cached one from being collected. On the other hand, I think if you were to resynthesize the number/string used as a symbol key and make a new symbol, that might allow you to observe whether the symbol had been collected. This doesn't seem like a huge problem to me but I forget the exact reasoning why weak references were unacceptable in the past; maybe it still applies to this.
In brief: allow Symbol's to be constructed with a single parameter, with the following behavior:
Motivation: the ability to construct equal Symbols gives us the necessary building blocks to build custom maps with semantics very similar to Simple Maps:
function ObjectMap() { this.map = {}; } SimpleMap.prototype.set = function(objKey, val) { this.map[new Symbol(objKey)] = val; }; SimpleMap.prototype.get = function(objKey) { return this.map[new Symbol(objKey)]; };
At a surface level, this seems more novelty than anything else, but I think it's a useful primitive for building more complex and robust features on top of Symbols. Thoughts?