JavaScript Talents
Composable Units Of Reuse via Delegation Proxies
aka Roles, Mixins, Traits

Flight Mixins ... Anyone?
var Enumerable_first = (function trait () {
return (function applicator () {
this.first = function first () {
return this[0];
};
});
}());
var Enumerable_last = (function trait () {
function last () {
return this[this.length - 1];
}
return (function applicator () {
this.last = last;
});
}());Flight Mixins ... Anyone?
var bazList = ["foo", "bar", "baz"];
var dogList = ["the", "lazy", "dog"];
// - `first` always gets assigned its very own method.
Enumerable_first.call(bazList);
Enumerable_first.call(dogList);
// - `last` also reserves its own slot, but
// will hold a reference into the closure.
Enumerable_last.call(bazList);
Enumerable_last.call(dogList);
console.log(bazList.first === dogList.first); // `false`;
console.log(bazList.last === dogList.last); // `true`;How about a nicer syntax ...
trait Enumerable_first {
applicator() {
this.first = function () {
return this[0];
};
}
}
trait Enumerable_last (
function last () {
return this[this.length - 1];
}
applicator() {
this.last = last;
}
}... backed by an ES3 library?
var
Enumerable_first = Trait.create(function (use, applicator) {
applicator(function () {
this.first = function () {
return this[0];
};
});
}),
Enumerable_last = Trait.create(function (use, applicator) {
function last () {
return this[this.length - 1];
}
applicator(function () {
this.last = last;
});
});-
"Trait Composition Language"
-
Composable behavior ... "Traits from Traits"
-
Conflict resolution of equally named functionality
-
... hhmh, and where does the code-reuse come from?
Apply rules
trait CompositeTrait { // trait declaration.
use { Trait_A, Mixin_B, Applicable_C }
//apply { Mixin_B }
apply { Applicable_C, Trait_A }
}
var CompositeTrait = trait { // trait expression.
use { Mixin_B, Applicable_C }
apply { Mixin_B:sanitize }
apply { Applicable_C:rerender }
}use {..} apply {..}
trait MinimumObservable { // trait declaration.
use { Observable_SignalsAndSlots }
apply all without { hasEventListener, removeEventListener }
}
var NoHasObservable = trait Observable { // named trait expression.
use { Observable_SignalsAndSlots }
apply { Observable_SignalsAndSlots } without { hasEventListener }
}use{..} apply all
use{..} apply all without {..}
use{..} apply {..} without {..}
Apply rules
trait Talktive_AB {
use { Talktive_A, Talktive_B }
apply { Talktive_A:smallTalk }
apply { Talktive_B:smallTalk } as { talk }
apply { Talktive_A:bigTalk } before { Talktive_B }
}
var talker = Talktive_AB.call({});
talker.talk(); // console does log : " bbb "
talker.smallTalk(); // console does log : " aaa "
talker.bigTalk(); // 1stly console does log : " AAA "
// 2ndly console does log : " BBB "use{..} apply {..} as {..}
Apply rules
use{..} apply {..} after {..}
use{..} apply {..} before {..}
trait withCompositeView {
use { withView_A, withView_B, withView_C }
apply { withView_A:register }
before { withView_B } before { withView_C }
apply { withView_A:initialize }
after { withView_B } after { withView_C }
apply { withView_C:render }
before { withView_B } after { withView_A }
}Apply rules
var view = withCompositeView.call({});
view.register(); // behavior's execution order : A-B-C
view.initialize(); // behavior's execution order : C-B-A
view.render(); // behavior's execution order : A-C-BAll of the proposed trait composition functionality and its syntax gets proved by an already existing ES3 compatible library ...
Apply rules
var
CompositeTrait = Trait.create(function (use, applicator) {
use(Trait_A, Mixin_B, Applicable_C)
//.apply(Mixin_B)
.apply(Applicable_C, Trait_A);
}),
CompositeTrait = Trait.create(function (use, applicator) {
use(Mixin_B, Applicable_C)
.apply(Mixin_B, "sanitize")
.apply(Applicable_C, "rerender");
});use(..).apply(..)
var
MinimumObservable = Trait.create(function Observable () {
use(Observable_SignalsAndSlots)
.apply.all.without("hasEventListener", "removeEventListener");
}),
NoHasObservable = Trait.create(function Observable () {
use(Observable_SignalsAndSlots)
.apply(Observable_SignalsAndSlots).without("hasEventListener");
});use(..).apply.all
use(..).apply.all.without(..)
use(..).apply(..).without(..)
Apply rules
var Talktive_AB = Trait.create(function (use, applicator) {
use(Talktive_A, Talktive_B)
.apply(Talktive_A, "smallTalk")
.apply(Talktive_B, "smallTalk").as("talk")
.apply(Talktive_A, "bigTalk").before(Talktive_B);
});
var talker = Talktive_AB.call({});
talker.talk(); // console does log : " bbb "
talker.smallTalk(); // console does log : " aaa "
talker.bigTalk(); // 1stly console does log : " AAA "
// 2ndly console does log : " BBB "
use(..).apply(..).as(..)
Apply rules
use(..).apply(..).after(..)
use(..).apply(..).before(..)
... and some trait composition examples on JSFiddle.
... got it, but what is it with this applicator again? And how, in the end, do I compose objects/types?
applicator
trait withFirstLastEnumerable {
function first() { return this[0]; }
function last() { return this[this.length - 1]; }
applicator() {
this.first = first;
this.last = last;
}
}
trait withEnumerableListProxy {
applicator(list) {
withFirstLastEnumerable.call(list);
this.first = function () { return list.first(); };
this.last = function () { return list.last(); };
}
}applicator ‧ call / apply
local functions, trait composition and stateful traits
class EnumQueue {
constructor() {
var
list = [],
queue = this;
queue.enqueue = function(item) {
return (list.push(item) && item);
};
queue.dequeue = function() {
return (list.shift());
};
withEnumerableListProxy.call(queue, list);
}
}applicator ‧ call / apply
local functions, trait composition and stateful traits
Trait Manual / Cheat Sheet
Library Example
var
withFirstLastEnumerable = Trait.create(function (use, applicator) {
function first() { return this[0]; }
function last() { return this[this.length - 1]; }
applicator(function () {
this.first = first;
this.last = last;
});
}),
withEnumerableListProxy = Trait.create(function (use, applicator) {
applicator(function (list) {
withFirstLastEnumerable.call(list);
this.first = function () { return list.first(); };
this.last = function () { return list.last(); };
});
});applicator ‧ call / apply
local functions, trait composition and stateful traits
JavaScript Talents
Composable Units Of Reuse via Delegation Proxies
aka Roles, Mixins, Traits
Thank You.
JavaScript Talents - Composable Units of Reuse via Delegation Proxies
By Peter Seliger
JavaScript Talents - Composable Units of Reuse via Delegation Proxies
raw presentational Trait/Talent syntax sketch for 2017.jsunconf.eu. Each of the embedded JSFiddle examples runs in your browser. The embedded Jasmin test specification fails only at specs that rely on class syntax and fat arrow functions but do not get them provided by clients that run such tests. Have also a look on "Refactoring legacy mixin-based class hierarchies" at Stack Overflow ... http://stackoverflow.com/questions/43027388/refactoring-legacy-mixin-based-class-hierarchies
- 2,057