Native Javascript example for fulloo.info

38 views
Skip to first unread message

Matthew Browne

unread,
Aug 18, 2017, 7:42:43 PM8/18/17
to object-co...@googlegroups.com

I was thinking that it would be good for a Javascript example to be included in the list of official examples at http://fulloo.info/Examples/, since Javascript is a popular language has pretty good support for DCI. Most of the examples on that page are native implementations that don't involve source code transformation, which makes sense because it's a gentler introduction and not everyone will want to commit to additional tools. (There's already a link to my babel-dci source code transformation library on the wiki.)

I would like to contribute the native JS example, I just would like the group's feedback on which implementation would be preferable:

1. A regular method injection implementation, similar to Ruby but with the option of manually unbinding the roles after the Context execution completes.

2. Method injection using symbols, introduced in ECMAScript 6.

I'm leaning toward #2, which has a few advantages:

  • It guarantees that there will be no name clashes between same-named role methods, meaning there's no need to worry about unbinding (removing injected methods)

  • The symbols can't be directly accessed outside the scope where they're defined. That means they can be private to the Context. The only way to access them from outside is via reflection (e.g. Object.getOwnPropertySymbols())

  • Because of the above points, there are no workarounds necessary to support nested contexts, even if there are name clashes

The main disadvantage is that the use of symbols requires a different syntax than a regular property access, which effectively means that there's a different syntax for calling role methods than calling instance methods. Here's the TransferMoney context implemented using symbols:

import Account from './Account';
const transfer = Symbol('transfer'),
withdraw = Symbol('withdraw'),
deposit = Symbol('deposit');
export default function TransferMoney(sourceAccount, destinationAccount, amount) {
const roles = {
banker: {
[transfer]() {
sourceAccount[withdraw]();
destinationAccount[deposit]();
}
},
sourceAccount: {
[withdraw]() {
if (this.balance < amount) {
throw Error('Insufficient funds');
}
this.decreaseBalance(amount);
}
},
destinationAccount: {
[deposit]() {
this.increaseBalance(amount);
}
}
};
// Role binding
const banker = {};
Object.assign(banker, roles.banker);
Object.assign(sourceAccount, roles.sourceAccount);
Object.assign(destinationAccount, roles.destinationAccount);
// Run the use case
banker[transfer]();
}


The full code (including an Account context implemented using ledgers) is here:
https://github.com/mbrowne/dci-js-examples/tree/master/TransferMoney/src

Symbols work in the latest versions of all major browsers (both desktop and mobile) except Internet Explorer, but that's been superseded by Microsoft Edge.

It would be ideal of course if both role methods and instance methods could be accessed using the same dot notation, but I'm thinking this might be an acceptable tradeoff given the advantages above.

To be clear, without symbols, the code would look like this:

const roles = {
banker: {
transfer() {
sourceAccount.withdraw();
destinationAccount.deposit();
}
},
sourceAccount: {
withdraw() {
if (this.balance < amount) {
throw Error('Insufficient funds');
}
this.decreaseBalance(amount);
}
},
destinationAccount: {
deposit() {
this.increaseBalance(amount);
}
}
};


I welcome any feedback, and I hope we can get a Javascript example (and ideally more than one of course) on http://fulloo.info/Examples/.

Thanks,
Matt

Matthew Browne

unread,
Aug 18, 2017, 9:57:05 PM8/18/17
to object-co...@googlegroups.com

P.S. Some of you may recall that I previously posted a different native JS implementation that also (mostly) solves the sticky injection problem. But I regard that as more of an experiment, and not ideal for production code because you have to prefix all the role identifiers with an identifier for the context, and if you forget to do so anywhere it won't work. So symbols are far preferable.

James O Coplien

unread,
Aug 19, 2017, 5:51:20 AM8/19/17
to object-co...@googlegroups.com
Parallelism with existing examples is a good thing, so even as much as we love to hate it, the accounts example works for me.


--
You received this message because you are subscribed to the Google Groups "object-composition" group.
To unsubscribe from this group and stop receiving emails from it, send an email to object-composit...@googlegroups.com.
To post to this group, send email to object-co...@googlegroups.com.
Visit this group at https://groups.google.com/group/object-composition.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages