Merging Bind Syntax with Relationships
What about protocols?
Can you elaborate? I know that Russell Leggett did some work along those lines a while ago (which really inspired the merge idea), but can you describe exactly what you mean?
Note though, that since behavior of referenceGet
is completely arbitrary,
you could (for instance) create a "reference name" object which traverses
up the prototype chain looking for a certain method name, and returns some
fallback method if nothing is found.
When you asked about discussion and this ran into my mind :)
I remember it was discussed here esdiscuss.org/topic/protocol-library-as-alternative-to-refinements-russell-leggett, ( the syntax in gist.github.com/genericallyloud/7086380 )
Do the semantics proposed above work with what's proposed there?
The "using the function as an extension method" seems pretty similar. However , Russell's work proposes a form of polymorphic dispatch based on the extended type. For example:
let dmot = new DoingMyOwnThing("Bob");
dmot::map( n => n * 3;) // calls method `map` of the DoingMyOwnThing
class instead of using the protocol method
This is really useful behavior that solves a few very real problems for me (it's real extension methods) - I think it would be very beneficial for discussions about bind syntax to allow or at least consider this.
I remember it was discussed here esdiscuss.org/topic/protocol-library-as-alternative-to-refinements-russell-leggett, ( the syntax in gist.github.com/genericallyloud/7086380 )
Do the semantics proposed above work with what's proposed there?
That's it - thanks for the link!
Yes - it could definitely work. Russell didn't actually an implementation for the his Protocol function, but using this proposal, the "methods" property of the resulting "protocol" object could be a dictionary of custom "reference name" objects.
Leaving aside all of the gory dispatch details, it might look something like this:
class Protocol {
constructor(...names) {
this.methods = {};
for (let name of names)
this.methods[name] = this._createMethod(name);
}
_createMethod(name) {
return {
[Symbol.referenceGet]: target => {
// 1. If target has an own property of "name", return it.
// 2. If target's type matches an extension of the protocol,
// return the protocol method.
// 3. If the target has a method of the same name somewhere up
// the prototype chain, return it.
// 4. If a default has been defined, return it.
// 5. Otherwise, return undefined.
}
};
}
}
I'm not sure to what extent this has been discussed previously, but I think we should consider merging relationships and bind syntax.
The relationships strawman introduces two new built-in symbols: @geti and @seti. I will instead use the more descriptive names:
Symbol.referenceGet
andSymbol.referenceSet
.The basic idea is that arbitrary objects can be used as the "referenced name" in a Reference object. When GetValue or PutValue is called on those kinds of reference objects, behavior is delegated to the functions defined on the "reference name" object at the appropriate symbol. If the required method is not defined on the name object, then an exception is thrown.
The operator "::" creates such a reference object.
The following code should illustrate the idea: