Skip to content

Deep protocols: Generalize static by supporting provided members on subobjects? #75

@LeaVerou

Description

@LeaVerou

In #69 we've been discussing the problem that the current version of protocols is constructor-centric, with provided members being added/checked on .prototype and only static members on the object itself, which means the implements operator does not work on instances. Another idea has been to default to adding provided members on the object itself, and static members on .constructor which would mean doing Protocol.implement(C.prototype, P) to get the current functionality.

While I would be opposed to dropping static with no alternative, because I think it's important for protocols to be atomic (you should not need to pull in multiple protocols to implement a single piece of functionality), I wonder if we could generalize it and make this a user choice.

Reusing static made a lot of sense when keeping syntax close to class definitions was a design goal.
However, with protocols progressively being a larger departure from class syntax (we recently resolved they cannot use class fields, we've been discussing dropping extends, etc), reusing static seems to provide less value.

What if instead of static, we supported a concept of "some provided members are attached to subobjects"?
I.e. instead of this:

protocol P {
	foo () {}
	static bar () {}
}

To be able to do Protocol.implement(C, P), you'd have this:

protocol P {
	on prototype {
		foo () {}
	}
	// implicit on this
	bar () {}
}

Or, to enable Protocol.implement(C.prototype, P) (which would also make c implements P possible) you'd define it like this:

protocol P {
	foo() {}
	on constructor {
		bar () {}
	}
}

Any on xxx members could become implicit requires, perhaps with the additional constraint of being objects.

Then whether to define a constructor-first protocol or an object/instance focused protocol becomes a user choice, rather than a language choice.
With sufficient introspection (#55), you could even create a protocol that turns another protocol "inside out", having both versions.

There could also be a requires on syntax for required members.

The class head syntax would just assume one of the two formats (probably the one that is installed on prototypes).

In addition to addressing the instance/static conundrum, this allows expressing protocols that are not currently possible to express, as they depend on requiring subobject members or installing members on subobjects.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions