Closed koresar closed 8 years ago
docs/stamp-specification.md
] that allows you to create factories (called stamps) that can be composed together.You can have only one initializator (aka constructor). In stampit you can have as many as you want.
- [x] Additional point: You should never export constructors from modules because they couple all call sites to the constructor implementation.
The benchmarks are fast. Object creation is optimized because of using the new keyword and omitting _.extend for each object created.
We can reference those functional mixins in stamp wikipedia page. Huh?
I don't think we need to address functional mixins in our docs, and the wikipedia page has been deleted. Apparently we need to get more people writing about stamps so there are more sources than just my book. ;)
Can we close this issue?
Functional mixins got continuation. With ES7 decorators it looks very much alike composables but with a different syntax. Read here: http://raganwald.com/2015/06/26/decorators-in-es7.html The composition syntax looks like this:
@BookCollector @Author
class BookLover extends Person {};
Where BookCollector
, Author
are composable behaviors (mixins) and the Person
is ES6 class.
I see several downsides of this approach. Anyone else see them?
Ok so I'm new to ESNext and very very new to the stamps concept, but I can't seem to find how any of this can't be accomplished without decorators (and maybe also Reflection and Proxies which I know very little about), save for being able to instantiate a stamp without using new
. So to answer your question, I don't think I can see any downsides immediately but I'm probably overlooking something.
https://github.com/wycats/javascript-decorators has some examples showing how to decorate classes not only in the way your example gives above, but with arguments, and also to decorate methods and properties by using decorators inside a class. This repo is the spec used by Babel's 'experimental' (used widely) implementation of decorators.
I'll grab a few examples from there for reference:
@isTestable(true)
class MyClass { }
function isTestable(value) {
return function decorator(target) {
target.isTestable = value;
}
}
Passing an argument - factories here we come!
class C {
@enumerable(false)
method() { }
}
function enumerable(value) {
return function (target, key, descriptor) {
descriptor.enumerable = value;
return descriptor;
}
}
So it seems that you can use decorators as factories and also to enumerate classes. This allows you to avoid class inheritance with an incredible degree of flexibility, and leverage the power of javascript's prototypical inheritance powers very similarly to what stamps achieves.
Also, because decorators use Object.defineProperty in a way that precedes your defined class, you could use this to backfill and overwrite class properties in your constructor() method. For example:
@annotation
class MyClass {
// override the decorator-provided property at the constructor() level so your class can do things with it after instantiation
constructor(){
this.isMyClass = true;
}
// or you could even override a property at the getter level!
get annotated(){
return `we don't need no annotation`;
}
}
function annotation(target) {
// Add properties to target
target.annotated = true;
target.isMyClass = false;
}
Lastly, the descriptor argument in a decorator function has some niceties.
let descriptor = {
value: specifiedFunction,
enumerable: false,
configurable: true,
writable: true
};
(To be honest I don't totally understand this yet but the spec has some nice examples)
And one last thing - because stamps are a specification, it is quite possible that a set of convenience decorators/etc could be used to create stamps!
I wonder if someone could create a minimalist ESNext implementation of the stamp concept with all the desired bells and whistles, using as much of the es6/7/etc spec that is available to, say, Babel, as is possible.
Once 'desugared' it would probably look similar to this library!
Looking forward to someone proving me wrong, because I've only scratched the surface with all of this yet!
Let me start with a quote:
social networks rank strategies prioritize the popular and habitual
I would rephrase to:
people prefer the popular and habitual
Classes are habitual. Decorators are popular in C# and Java (and few other languages). It's logical to see people (re)implementing the same in all other new languages like JavaScript.
The downsides listed by Eric above are pretty much applicable to the decorators too.
It is a very, very hard choice. Trust me. I did that for years in C#.
Also, stampit deliberately avoid class
, constructor
, new
and instanceof
keywords applications to stamps. These are antipatterns in JS (see Eric's link above).
Additionally, while applying decorators you need to know which object they are applicable to: class, method, data, etc. Whereas in stampit you just .compose()
.
The JavaScript property descriptors (aka Object.defineProperty
) with all the bells and whistles are coming to stampit v3. And they are already implemented and described here: https://github.com/stampit-org/stamp-specification
Saying all that I am thinking of using decorators and stamps together. They can be a good match!
There is a 4 years old term: functional mixin
The idea behind it is very similar to stampit's. - "has-a" or "uses-a" relationships between composed components.
Correct me where I'm wrong.
Differences to stampit I found so far (please, add up):
.call(prototype)
calls below) and somewhat bulky.init()
's.RoundButton
above. Whereas stamp's.create(refs)
method argument is merged into object instance.new
keyword and omitting_.extend
for each object created.Features stampit have but the proposed functional mixins don't.
init()
function(s) can return promise, which then is being resolved to an object instance.stamp.static()
- this helps a lot to do BDD style coding. See this example.stamp.props()
.