Giter Site home page Giter Site logo

Comments (6)

jneuendorf avatar jneuendorf commented on August 24, 2024

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.

nicolas-van avatar nicolas-van commented on August 24, 2024

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.

jshthornton avatar jshthornton commented on August 24, 2024

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.

jshthornton avatar jshthornton commented on August 24, 2024

@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.

jneuendorf avatar jneuendorf commented on August 24, 2024

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.

nicolas-van avatar nicolas-van commented on August 24, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.