Union, intersection, difference, and more are coming to JavaScript Sets
sonarsource.com
sonarsource.com
[1] https://github.com/tc39/notes/blob/HEAD/meetings/2022-11/nov...
A difference is like performing a LEFT JOIN.Why won't it work on objects when the language very good for creating objects with any ceremony.
EDIT:
By won't work i mean you are left with reference equality checks which I never felt useful.
Talking about other languages i worked with, In Java and C# you can override equals method in which you specify which property to check equality on, (even python you can do that with __eq__ i think).
const set = new Set();
const x = { id: 'some object' };
foo.add(x);
foo.has(x);
> true
I'm guessing you're taking issue with the fact that it uses reference equality instead of structural equality, which can definitely be a pain point. There's a proposal to improve the situation with "Records and Tuples" [0], but it's been stuck in committee hell for years.That and other programming languages provide a mechanism to specify a property to check for value equality.
I don't understand the point of this. What good is an object in a Set if it can't be deduped?
With this and so much else in the core language, I wish they just incorporated lodash into Ecmascript and called it a day. https://lodash.com/docs/4.17.15#uniqWith (the example is specifically for comparing objects by value)
> but it's been stuck in committee hell for years.
It's been like this for more than a decade, too. I've never seen a popular language evolve SO slowly, whether it's with Sets, or things like the Temporal API or TypeScript or JSX or bundlers. Almost all the innovation in JS seems to come from third parties forced to hack them in, whether through vendor prefixes, jQuery, or later ecosystems like npm libs and React. In that same time period, PHP improved by leaps and bounds, entire languages like Rust came out of nowhere and gained a foothold, WASM was developed, etc. And lodash is STILL around and still useful.
It's so frustrating to watch.
I think the inverse can also be true, where the core language / TC39 is over-cautious with feature adoption, leading to extreme ecosystem fragmentation and eighteen vendors reinventing the same three wheels every year.
As for a first-party type system, would you want it to basically be TypeScript, or something else? If the former, then we'd lose a lot of features and such, because the core language, not being a single vendor, can't move as fast as TypeScript does. If the latter, then it would be necessary to define what, and in all likelihood different people would want different and incompatible things.
Aside from performance, true native immutability would bring huge improvements to how JS programmers can reason about their code. Not having to worry about mutation makes a whole class of possible bugs disappear. Having to rely on third party libraries (or deep freezing manually) for immutability is really holding back the language.
As far as the pace, I think they do it about right. JS has hard requirements to be backwards compatible and has several canonical implementations, so adding new features should only be done after careful consideration. Letting users add features themselves and ensuring they have staying power and wide adoption is a good test.
An example of where I've found this useful is object cycle detection.
JavaScript is a secure language and therefore doesn't have the luxury of a language like C++ where you can mash two features in and declare their interaction "undefined behavior." Every new feature must eventually be considered in the context of every other feature.
If this is a bad way to do it, then why isn't TC39 working on a better way to implement protocols / traits in JS?
See `Symbol.keyEquality` - although that still shows what I feel is a misunderstanding about the direction at which the protocol should work. I don't want to be creating new types of maps and sets, I want existing ones to have controllable key equality. If it was for new types of maps and sets, I'd just implement a new Set class independent of JS builtins and be done with it. (Its not like the built in Set offers any rich features that I'd have a hard time replicating anyway)
Protocols (traits) should really be the cornerstone of TC39 work, IMO. They'll help with JavaScript's serious ecosystem compatibility issues.
const a = {}
const b = {}
const set = new Set([a])
set.has(a)
// true
set.has(b)
// falseconst a = { value: 1 } const b = { value: 1 }
const set = new Set([a, b])
set.size will be 2 as JavaScript checks for reference equality and has no mechanism check equality on a specific property
const set = new Set();
set.add({});
set.add({});
// Set has 2 items [{}, {}]
const a = {};
set.add(a);
set.add(a);
// Set has only 3 items [{}, {}, {}]
The actual problem here is that JavaScript doesn't have any way to override `equals` and `hashCode` like Java does, so there's no way to change this reference-equality behavior.But you can use Symbols for that. no ?
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
const s = new Set([1,2,3]);
The resulting instance of Set can be queried for something existing in the set, have items added to the set, and remove from the set. This doesn’t handle literal objects (e.g. a record) well, which isn’t idiosyncratic to JS as most languages treat objects as reference-ish. The solution be to use a literal String or Number identifier that can be looked up.I’m genuinely curious, what features from other languages do you want to see in this implementation?
In Java and C# you can override equals method in which you specify which property to check equality on, (even python you can do that with __eq__ i think). In JavaScript you are left with either primitives or objects with references equality checks.
In Python __hash__() needs to be implemented in order to put something in a set.
You cannot override that in Javascript, but you can roll your own set with custom hash function by wrapping a Map.
True. But you they can use a "known Symbol" to implement this feature.
IMHO it's better to be explicit in such a case. It's not complicated to implement your own set-like class that does exactly what you want.
Could you explain why that would be a footgun? JavaScript already has known Symbols like hasInstance which is kind of similar to this.
Most runtimes do this to prevent the need for a double lookup cost by doing "has" then "add."
It's a common pattern for when the set is used to either know when to or when not to do expensive work.
You cannot override the equality -operator but you can add simple short-named method "eq(anotherSet)" and perhaps variations of that.
It's not too much effort to create your own custom Set -subclass because it only needs to do what you need it to do that the built-in Set does not do. You can also perhaps find such an implementation on npm etc.
A perfect built-in Set would be great but being able to subclass the existing Set-class helps a lot already.
But my point is when you code an application you are not coding a library, but an app, so you only need to add the methods your app needs. You probably don't need to create an all-encompassing new Set-implementation that wins the library-of-the-year award. :-)
Maybe you just need to add a method named 'eq()'.
An added benefit of creating your own Set-subclass is you can put debugger-statements in its code to observe who uses it and how. You can put assertions in it to ensure only correct type of elements can be added to it etc.
I often used sets in Java as return-types or parameters to specify collections of unique items.
Profiling code over the years I noticed that, a lot of times the reason for a performance bottleneck was some hashcode calculation for a Set or Map.
So now I often use plain ol' ArrayLists.
Is there any magic quick way of doing this in modern JavaScript, or do I have to keep cutting+pasting a comparator I wrote everywhere?
[ [1,23], [11,1], [11,44], [22,4] ]
I'd consider this list "sorted", as the inner lists are sorted lexicographically. Except, if I gave this list to Javascript and asked it to sort it, it would cast each of the inner lists to strings, which (for example) leads to [11,11] < [1,1], as "[11,11]" < "[1,1]"
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
More leftie ideas infecting the language. It's political correctness gone mad.
Not the ties and hashtables of other languages.
With strict weak ordering, you really only have the ordering of to elements.
Ada took care of that polysemy between ordered and hash sets a long time ago.
But ya it took them to long to implement 'contains', but JavaScript requiring ordered sets while allowing multiple implementation details complicated it IMHO. Had they chosen a structure vs a time complexity it would have been easier to extend.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
bool set_contains_x = set.find(x) != set.end();That is not a contains() function. That is a search followed by a test for not not-found.
1+3 is logically equivalent to 4, but they are not the same. As just one example, the former contains an operation.
Is it any use to add them now? Are there people who use base JavaScript with absolutely no library?
And that's the nice thing about JS: because it keeps improving, many things that used to require a third party library no longer do.