Comments (6)
Hi,
I had the same problem. So I modified the ring.create function like so:
ring.create = function() {
// arguments parsing
var args = _.toArray(arguments);
args.reverse();
var props = args[0];
var parents = args.length >= 2 ? args[1] : [];
if (! (parents instanceof Array))
parents = [parents];
_.each(parents, function(el) {
toRingClass(el);
});
if (parents.length === 0)
parents = [ring.Object];
// constructor handling
var cons = props.constructor !== Object ? props.constructor : undefined;
props = _.clone(props);
delete props.constructor;
if (cons)
props.__ringConstructor__ = cons;
else { //retro compatibility
cons = props.init;
delete props.init;
if (cons)
props.__ringConstructor__ = cons;
}
// create real class
var claz = function Instance() {
this.$super = null;
this.__ringConstructor__.apply(this, arguments);
};
claz.__properties__ = props;
// mro creation
var toMerge = _.pluck(parents, "__mro__");
toMerge = toMerge.concat([parents]);
var __mro__ = [claz].concat(mergeMro(toMerge));
//generate prototype
var prototype = Object.prototype;
// CUSTOM:
// defining hash for later use (-> static stuff)
var staticProps = {};
// END of CUSTOM
_.each(_.clone(__mro__).reverse(), function(claz) {
var current = objectCreate(prototype);
_.extend(current, claz.__properties__);
_.each(_.keys(current), function(key) {
var p = current[key];
// CUSTOM:
// magic for in-place declaration of static vars
if (key === "_static") {
_.each(p, function(v, k, obj) {
claz[k] = v;
staticProps[k] = [v, claz];
});
return;
}
// END of CUSTOM
if (typeof p !== "function" || ! fnTest.test(p) ||
(key !== "__ringConstructor__" && claz.__ringConvertedObject__))
return;
current[key] = (function(name, fct, supProto) {
return function() {
var tmp = this.$super;
this.$super = supProto[name];
try {
return fct.apply(this, arguments);
} finally {
this.$super = tmp;
}
};
})(key, p, prototype);
});
current.constructor = claz;
prototype = current;
});
// remaining operations
var id = classCounter++;
claz.__mro__ = __mro__;
claz.__parents__ = parents;
claz.prototype = prototype;
claz.__classId__ = id;
// construct classes index
claz.__classIndex__ = {};
_.each(claz.__mro__, function(c) {
claz.__classIndex__[c.__classId__] = c;
});
// class init
if (claz.prototype.classInit) {
claz.__classInit__ = claz.prototype.classInit;
delete claz.prototype.classInit;
}
_.each(_.chain(claz.__mro__).clone().reverse().value(), function(c) {
if (c.__classInit__) {
var ret = c.__classInit__(claz.prototype);
if (ret !== undefined)
claz.prototype = ret;
}
});
// CUSTOM:
// static / class methods / properties
_.each(_.clone(__mro__).reverse(), function(parent, idx, list) {
// NOTE: parent must NOT be iterated with _.each() because it isArrayLike and will therefore not loop any keys!
for(var key in parent) {
if (key.slice(0, 2) !== "__" && key !== "prototype") {
var prop = parent[key];
(function(key, prop) {
staticProps[key] = [prop, parent];
})(key, prop)
}
}
});
// actual static inheritance
_.each(staticProps, function(data, key, obj) {
if (key !== "prototype") {
var prop = data[0];
var clss = data[1];
// function => wrap it and call function with correct context and arguments
if (prop instanceof Function) {
claz[key] = function() {
return clss[key].apply(claz, arguments);
};
}
// no function => copy reference
else {
claz[key] = clss[key];
}
}
});
// END of CUSTOM
return claz;
};
I wrapped the changed parts in commented CUSTOM tags.
Additionally I added the possibility to define static vars not only after the class definition but also directly anywhere in the object that's passed to ring.create() (where the class body is defined). In order to do so just add the key _static anywhere you want to declare something static:
ring.create([parent1, parent2], {
constructor: function() {},
// ...
_static: {
staticVar: 3
},
// ...
});
If I remember I will create a pull request next week (unless it's already applied by then) ;)
Hope that helps
from ring.js.
Let me think about it. I'll see if it's a feature worth including in ring and if it would cause problems.
But to be honest I predict that it would cause lot of problems due to multiple inheritance.
from ring.js.
I agree it would cause a lot of issues. It is definitely a nice to have feature for static vars.
For now I have worked around the problem by using a separate object literal to store such data in. Create for enums, not nice for static class vars.
from ring.js.
@jneuendorf a pull request for that would be great. I think if you really want to get it included @nicolas-van will need it thoroughly unit tested.
from ring.js.
Alright. I'll also think about it a little bit more.
Why do you think it will cause problems?
Here is the basic idea:
For each class I go through the reversed mro and look for static vars which are saved to a dictionary of the form: {name: [value, class]}. That means that when having multiple identically named static props (even across classes) the latest one will be taken (<=> the first in the mro).
For properties a reference is saved to that last occurrence, for functions a wrapper function is created that class the according function in the mro (=> last occurrence again) is called with the passed arguments and the inheriting class as context.
But this whole stuff is done only if the static var is not overridden in the inheriting class. (<- this feature is not implemented in the code above! but it's already done in the code I will provide for the pull request).
So possible problems are:
- If a static non-function property S of a class X is changed after Y = ring.create(...) was called with X as one of its parents, Y.S will still point to the old value X.S
- Is that actually a problem or is this behaviour wanted? I don't know if we should take care of that...
- in order to prevent that from happening I could (for static non-function properties) create a property with a getter and setter, so that the getter does a lookup in the mro
(in contrary)
- If a static non-function property S of X is not a primitive type (let's say {a: 10}) and Y extends X then their X property points to the same object => changes are seen in both classes
- maybe one would like to not have the system behave like that but I again think this should not be part of the ring.js library (=> the user should take care of cloning objects instead of us)
from ring.js.
Yeah, but you don't know the whole story. I'm planning for version 2.1 to add a feature to modify the prototype of existing classes and have it impact the child classes. So each time I modify the code I think about that future feature.
Another, more important, point for me is the "purity" and usefulness of such a feature. As far as I know, static members are not much more than syntactic sugar in a lot of languages and are not really related to OO programming.
In C++ static functions are mostly useful because they allow access to private members of a class (useless in JavaScript). In Java they are used in place of function because... you know... there are no functions in Java. When I have time I'll dig a little to understand the rationale to implement it in Python.
Until now I don't see the usefulness of having a member of a class that gets "inherited" and can be overridden in child classes, knowing that it's extremely rare to get that member other than by specifying explicitly the name of that class (thus it's really not different than a simple function or variable).
If you want to argument to try to convince me I am open. Just know that I don't want to include that feature just to "do like Java".
from ring.js.
Related Issues (14)
- Problem with length HOT 1
- How to invoke superclass initialisation? HOT 1
- Invoke Base Method HOT 2
- Ring along with others HOT 3
- Without underscore? HOT 9
- FAQ: How can this.$super possibly work w/o significant performance penalty? HOT 1
- Multiple inheritance method resolution HOT 4
- Static attributes HOT 1
- Explanation of spec failure (bad equality) HOT 1
- Weird Constructor Name HOT 1
- How to achieve the private property HOT 1
- Recommended to increase the storage constructor parameters HOT 3
- Documentation link on homepage is a 404 HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ring.js.