Open
Description
Often it makes sense for a protocol to have optional fields that can be omitted entirely (but considered when they're used) but still included conceptually as part of the protocol.
For example:
protocol Hash {
hash; // Not optional
// Hashing might be expensive so objects can report they can be cached
// if they want
?cacheable; // Optional, syntax not important
}
const hashes = new WeakMap()
function hash(value) {
if (hashes.has(value)) {
return value
}
if (!(value implements Hash)) {
throw new Error(`Can't hash ${ value }`)
}
const hash_ = value[Hash.hash]()
if (value[Hash.cacheable] && value[Hash.cacheable]()) {
hashes.set(value, hash_)
}
return hash_
}
class HashTable { ... }
class Point implements Hash {
constructor(x, y) {
this.x = x
this.y = y
}
[Hash.hash]() {
return this.x + this.y
}
[Hash.cacheable]() {
return true
}
}
class Tuple implements Hash {
constructor(...args) {
this._tuple = args
}
[Hash.hash]() {
return this._tuple.reduce((acc, hash) => acc + hash, 0)
}
// As immutable can cache
[Hash.cacheable]() {
return true
}
}
Array.prototype[Hash.hash] = function() {
return this.reduce((acc, hash) => acc + hash, 0)
}
// Hash.cacheable needn't be implemented as Array is mutable
Reflect.implement(Array.prototype, Hash)
Obviously this is a trivial example but with more complex protocols this would see better benefit.
For example if Iterator were a protocol:
protocol Iterator {
'next'; // Not optional
?'return'; // Optional
?'throw'; // Optional
}
Metadata
Metadata
Assignees
Labels
No labels