... I think Typescript only allows unique symbols, not global ones. Is this correct?
All symbols are unique. That is invariant.
How to scope and access symbols is another question.
There are two ways to create symbols:
First way: Symbol(mnemonic?:string)
, e.g.
const x = Symbol('optional name')
const y = Symbol('optional name')
assert(x!==y) // pass
Every call to Symbol(...)
creates a unique symbol.
The mnemonic
is just a convenience property for debugging, etc.
Two symbols can have the same mnemonic without being the same symbol.
console.log(x.toString()) // 'Symbol(optional name)'
assert(x.toString()===y.toString()) // pass
assert(x!==y) // pass
When symbols are created in this way they only exist as long as they are referenced in user code - just like other objects, they can be garbage collected.
Second way: Symbol.for(globalKey:string)
, e.g.
In file 'x.js', with NO import
/require
statements at all
const x = Symbol.for('my.global.symbols.1')
export x
In file 'y.js', with NO import
/require
statements at all
const x = Symbol.for('my.global.symbols.1')
export y
In file 'z.js'
import {x} from './x'
import {y} from './y'
assert(x===y) // pass
const z = Symbol.for('my.global.symbols.1')
assert(x===z) // pass
In this case, a unique global symbol is created for each UNIQUE global key passed as the globalKey
parameter to Symbol.for(globalKey:string)
- from any file.
The symbol instance is stored in opaque global space, as though there were an opaque global map:
Symbol.for(globalKey:string):symbol{
if (globalSymbolMap.has(globalKey)
return globalSymbolMap.get(globalKey)
else{
const s=Symbol(globalKey)
globalSymbolMap.set(globalKey,s)
return s
}
}
(although that might not be how it is actually implemented).
Here is what MDN says about Symbol.for()
:
In contrast to Symbol(), the Symbol.for() function creates a symbol available in a global symbol registry list. Symbol.for() does also not necessarily create a new symbol on every call, but checks first if a symbol with the given key is already present in the registry. In that case, that symbol is returned. If no symbol with the given key is found, Symbol.for() will create a new global symbol.
About garbage collection for these globally managed symbols - I don't know which of the following are true:
When a globally managed symbol is no longer referenced by any user code (i.e., not including the reference from the opaque global 'virtual' map) then it may be garbage collected.
Once created, globally managed symbols remain in the opaque global 'virtual' map until end of program life.
From the perspective of user code 'logic', there would be no difference between the two - it's entirely an implementation issue. However, performance, including memory usage, would differ. My guess is that some garbage collection is enabled.