This would carry roughly the same kind of semantics as DOMTokenList, but also returning a boolean based on whether it previously existed for convenience and utility, something like this:
Set.prototype.toggle = function (value, include = this.has(value)) {
if (include) {
return this.delete(value);
} else {
const prev = this.size;
this.add(value);
return this.size !== prev;
}
};
I've personally had as much use for it outside the DOM as in, so it'd be very useful to have. Also, engines could optimize this to always look up the value and then afterwards make the determination on whether to add or remove the value, to save a bunch on branches and code size, resulting in far less overhead.
I've had a lot of places where I either need a straight toggle (toggle the current value) or a force toggle (set the presence to a computed boolean), and a built-in .toggle() would make that code a lot nicer to read.
The basic "toggle" behavior (with no second parameter) is reasonable though I'm not likely to champion it myself.
But for the second parameter, how is "force toggle" any different from set[include ? 'add' : 'delete'](element)? I would prefer reading that rather than figuring out what this optional second boolean parameter is doing.
The two-parameter form isn't any different, but from an implementation perspective, both simple toggling and toggling by presence are extremely similar:
Set.prototype.toggle = function (value, force) {
// The only difference between the two methods
const forceByExistence = arguments.length < 2
if (!forceByExistence) force = Boolean(force)
const location = getEntryLocation(this, value)
if (forceByExistence) force = !hasValue(location)
if (force) {
if (!hasValue(location)) {
insertAtLocation(this, location, value)
return false
} else {
return true
}
} else {
if (hasValue(location)) {
removeAtLocation(this, location)
return true
} else {
return false
}
}
}
(I've implemented a few raw hash tables before. This is basically how they all work.)