Fun with Stamps. Episode 9. Detaching compose()
Hello. I’m developer Vasyl Boroviak and welcome to the ninth episode of Vasyl Boroviak presents Fun with Stamps.
TL;DR
You can detach a .compose() method to become the compose() standalone function because the .compose() method is not bound.
import ThirdPartyStamp from 'somewhere';const compose = ThirdPartyStamp.compose;// use it as regular compose function
compose({properties, method, initializers});
The problem
Have you ever had this problem when your code was using several implementations of promises in a single JavaScript application? Once I had Bluebird, Q, and native promises loaded and running in the same node.js process.
Here is how it’s typically happens:
import {readUser, readGroup} from ‘whatever’;
import Promise from 'q';export function getGroups(userId) {
const userPromise = readUser(userId); // returns bluebird return userPromise.then(user => {
const allGroups = user.groups.map(readGroup); // all bluebird
return Promise.all(allGroups); // Q promise!
});
}
I wish Promises specification would allow detaching the .then() method to a Promise constructor. Like this:
import {readUser, readGroup} from ‘whatever’;export function getGroups(userId) {
const userPromise = readUser(userId);
const Promise = userPromise.then; // detaching bluebird promise return userPromise.then(user => {
const allGroups = user.groups.map(readGroup);
return Promise.all(allGroups); // still bluebird!!!
});
}
Stamps’ solution
You can reuse compose() implementation by detaching the .compose() method from any stamp.
import ThirdPartyStamp from 'somewhere';const compose = ThirdPartyStamp.compose; // detaching
And use is as a regular compose() standalone function.
compose({properties, method, initializers, staticProperties, ...});
But for purity (and possibly Garbage Collection issues) it’s recommended cloning that function using JavaScript .bind(). You would strip off any attached properties as well.
const Stamp = ThirdPartyStamp.compose({methods: {foo() {}}});let compose = Stamp.compose;
console.log(compose.methods.foo); // [Function: foo]compose = compose.bind();
console.log(compose.methods); // undefined
Detaching compose() from an infected stamp
From the previous episode you learned that stamps can be infected with additional functionality. When you detach the .compose() method from an infected stamp the compose() function will still be infected.
For example we have this infected compose() which prints its all arguments:
function debuggerCompose(...args) {
console.log('Composing these:', args); args.push({staticProperties: {
compose: debuggerCompose
}}); return compose.apply(this, args);
}const InfectedStamp = debuggerCompose();
Let’s detach the .compose() form the InfectedStamp:
const compose = InfectedStamp.compose; // detaching
And try creating a stamp from it to see if it’s still infected or not:
const NewStamp = compose();
The code above will print:
Composing these: []
This means that the NewStamp is still infected. New stamps created from it will also be infected:
const NewNewStamp = NewStamp.compose({properties: {bar: 2}});
Will print this:
Composing these: [ { properties: { bar: 2 } } ]
As you can see detaching doesn’t help to disinfect a stamp.
Disinfecting a detached compose()
It depends on how the infection is implemented. But generally, you can’t disinfect an infected compose().
- Episode 1. Stamp basics
- Episode 2. Dependency injection in FP
- Episode 3. Comparing with the ES2015 classes
- Episode 4. Implementing stamps yourself in 30 LOC
- Episode 5. Composition design pattern
- Episode 6. Statics — properties on stamps
- Episode 7. Early and late dependency injection
- Episode 8. Tracking and overriding composition
- Episode 9. Detaching compose() (this article)
- Episode 10. My stamp mental model
- Episode 11. Interfering composition
- Episode 12. New @stamp home
- Episode 13. Method collision control
- Episode 14. New @stamp/it as a replacement of Stampit
- Episode 15. The @stamp/ modules ecosystem
- Episode 16. TypeScript mix-in classes vs Stamps
- Episode 17. Easy 100% unit test coverage in JS
- Episode 18. Dependency injection paradise
- Episode 19. Java/C# abstract methods in JavaScript
- Episode 20. Stampit v4
- Episode 21. Private data in JavaScript. 4 ways using stamps
- Episode 22. JavaScript instanceof as composable stamp
- Episode 23. New stampit.js.org with all the docs
- Episode 24. New “name” feature