aka Roles, Mixins, Traits
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;
});
}());
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`;
trait Enumerable_first {
applicator() {
this.first = function () {
return this[0];
};
}
}
trait Enumerable_last (
function last () {
return this[this.length - 1];
}
applicator() {
this.last = last;
}
}
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;
});
});Composable behavior ... "Traits from Traits"
Conflict resolution of equally named functionality
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 {..}
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 {..}
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 }
}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 ...
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(..)
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(..)
use(..).apply(..).after(..)
use(..).apply(..).before(..)
... and some trait composition examples on JSFiddle.
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
aka Roles, Mixins, Traits
Thank You.