Fun with Stamps. Episode 19. Java/C# abstract methods in JavaScript
Hello. I’m developer Vasyl Boroviak and welcome to the nineteenth episode of Vasyl Boroviak presents Fun with Stamps.
TL;DR
The new @stamp/required
stamp (aka behaviour) which checks if a certain method/property/staticProperty/configuration/etc exists. Otherwise, it will throw something like “Required: There must be myMethodName in this stamp methods”
while creating an object instance from your stamp.
Why having this feature at all?
In Java/C# world people tend to think in terms of interfaces and their implementations. In JavaScript world it is rarely needed. Although, some object composition approaches (like traits.js) do have “abstract methods” feature.
On the other hand, what if your stamp have sense only if it was provided a property? In this case people typically create an initializer, which checks a property existence and then throws:
import stampit from '@stamp/it';const CheckMyPropertyExists = stampit({
init() {
if (!this.myProperty) throw new Error('myProperty is missing!');
}
});
To simplify Java/C# developers transition to stamps, and to remove that if-throw
boilerplate code, there is the Required
stamp — https://www.npmjs.com/package/@stamp/required
Converting Java/C# abstract methods to stamps
Java/C# code:
abstract class Dog {
abstract void jump(); // Insist jump() implemented by descendants
}
This code will throw at compilation time:
const dogInstance = new Dog();
Stamps:
import Required from '@stamp/required'; // Importing the stamplet Dog = Required.required({
methods: {
jump: Required // Insist jump() exists while creating an object
}
});
This code will throw at runtime (there is no compilation time in JS):
const dogInstance = Dog();
// Throws - “Required: There must be jump in this stamp methods”
But if we add the jump()
method it will be ok:
Dog = Dog.methods({
jump() { ... }
});const dogInstance = Dog(); // all good
And, of course, the jump()
method will be attached to the instance prototype:
const proto = Object.getPrototypeOf(dogInstance);
console.log(proto.jump); // "function"
Stamps have moar powers than outdated Java/C#
See code examples. Read comments!
Insist a property exists:
const RequiresOwner = Required.required({
properties: {
owner: Required // Insist .owner exists
}
});let Cat = stampit({ ... }).compose(RequiresOwner);
Cat(); // Throws!Cat = Cat.properties({ owner: 'Vasyl' });
const cat = Cat(); // ok
Insist a static property exists:
const RequiresReadFromDatabaseFactory = Required.required({
staticProperties: {
readFromDatabase: Required // Insist Cat.readFromDatabase exists
}
});let Cat = stampit({ ... }).compose(RequiresReadFromDatabaseFactory);
Cat(); // Throws!Cat = Cat.statics({
async readFromDatabase(id) {
return await someCatDatabase.get(id)
}
});
const cat = Cat(); // ok
Insist you gave your stamp a runtime name:
const MustHaveBeenNamed = Required.required({
staticPropertyDescriptors: {
name: Required // Insist stamp have a non default runtime name
}
});let Cat = stampit({ ... }).compose(MustHaveBeenNamed);
console.log(Cat.name); // "Stamp" <- the default name
Cat(); // Throws!import {setName} from '@stamp/named'; // name helper stampCat = setName('Cat').compose(Cat); // just another way to compose :)
console.log(Cat.name); // "Cat" <- the new name
const cat = Cat(); // ok
Have fun with stamps!
- 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()
- 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 (this article)
- 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