dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.09k stars 1.56k forks source link

JS Symbols can't be used as Dart map keys #47670

Open nex3 opened 2 years ago

nex3 commented 2 years ago

Passing an instance of JavaScript's Symbol class as a key to a Dart Map causes an error like the following:

Uncaught TypeError: J.getInterceptor$(...).get$hashCode is not a function
    at Object.get$hashCode$ (/home/nweiz/goog/sass/dart/build/npm/sass.dart.js:9370:42)
    at JsLinkedHashMap.internalComputeHashCode$1 (/home/nweiz/goog/sass/dart/build/npm/sass.dart.js:27589:16)
    at JsLinkedHashMap.internalSet$2 (/home/nweiz/goog/sass/dart/build/npm/sass.dart.js:27464:20)
    at JsLinkedHashMap.$indexSet (/home/nweiz/goog/sass/dart/build/npm/sass.dart.js:27454:15)
    at Object.fillLiteralMap (/home/nweiz/goog/sass/dart/build/npm/sass.dart.js:6698:16)
    at Object.LinkedHashMap_LinkedHashMap$_literal (/home/nweiz/goog/sass/dart/build/npm/sass.dart.js:13378:81)
    at Object.updateValuePrototype (/home/nweiz/goog/sass/dart/build/npm/sass.dart.js:5332:16)
    at Object.main (/home/nweiz/goog/sass/dart/build/npm/sass.dart.js:1890:9)
    at main1 (/home/nweiz/goog/sass/dart/build/npm/sass.dart.js:18701:9)
kevmoo commented 2 years ago

CC @rakudrama

rakudrama commented 2 years ago

Lets assume we make JavaScript symbols behave as a distinct Dart type that implements all the methods declared for Dart Object. There is a problem of how we implement some of these methods.

The Dart maps use hashCode, but there is no obvious way to give different JavaScript symbols different hashCode values. You can't store the hashCode on a property of a JavaScript symbol (it is not an object with properties, so JavaScript creates an Object wrapper, stores the property there, and then discards the temporary wrapper). You can't use a JavaScript symbol as a key to a JavaScript WeakMap. The implication therefore is that all JavaScript symbols have the same hashCode value and the map lookup degenerates to a linear lookup.

Another approach would be to treat JavaScript symbols specially in Dart maps. Strings are already treated specially (they have similar problems with hashCode). The downside of treating JavaScript symbols specially is that it would add another test on a hot path to handle an issue that is rare enough that has not been noticed until recently.

nex3 commented 2 years ago

Even linear lookup would be preferable to having an object that simply crashes your application if you put it in a Map. That said, why not set Symbol.protoype.get$hashCode to a function that returns the hash code of Symbol.toString()?