>> The trick is encapsulating the class definition as a whole inside the
>> contructor method (using bind() to preserve the lexical scope of the
>> containing class),

> Both of these actions seem very unfriendly to me. Having to define my
> entire object inside the constructor? Appending a bind(this) to every
> method I create? Private properties have questionable value if it is
> easy to use. If I have to go through a lot of work the value does not
> make up for the increased code complexity in my opinion.

First of all, if you have adopted proto as your base, and classical OO is the programming model you are consistently enforcing across the development cycle/project/team, then this is no extra work and in fact saves much effort via prototype.

Now, consider the following class and subclass (or Objects if that's what you prefer). To determine if proto makes it MUCH easier to achieve these various classical constructs (or not, as you claim), I'll create them using prototype and you create it without (making sure to obey the same private/public/instance/static/superclass/subclass object model as my classes). There are really only 3 prototype calls I'll make, just to isolate the comparison ( Class.create(), Object.extend(), and bind()). I'm interested to see which style looks cleaner and lends itself better to re-use and refactoring (and to be objective I'll qualify that with which style looks better to _other_ people, as I'm sure I'm biased towards my style and you towards yours). I'm not trying to turn this into any kind of battle, I just really think people are a) taking for granted the power of just those 3 simple functions, and b) not looking enough outside the box to really see what proto can do (or how much easier it can make certain things if classical OO is important to you, which for a good majority of people on this list I'm guessing it is).

Consider all that's really happening here... I'd really like to see a "cleaner" more concise version of all of this with just "standard" _javascript_ (which of course proto is, but just provides great helper methods for us).

myBase = Class.create();
        myBase.prototype = {
            initialize: function(name) {
                //private variables
                var _myPrivateName = name + " Arooney Doony";

                //public properties
                this.name = name;

                //private methods
                var _myNameIsJim = function() {
                    return name == "Jim";
                };

                //public (instance/privileged) methods (only available to instances of this class and have full access to private members)
                //NOTE: I use Object.extend here simply to encapsulate these methods in one place (bulk applying via object notation looks cleaner to me)
                Object.extend(this, {
                    sayHi: function(isOldBuddy) {
                        if (isOldBuddy)
                            alert("Heyyy, what's up, it's me... you know... you're old pal, " + _myPrivateName);
                        else
                            alert("Hi");
                    },

                    //maintain class level scope for methods needing to access other instance members
                    sayHiFromJim: function() {
                        this.sayHi(_myNameIsJim());
                    }.bind(this)
                });
            },

            //instance (non-privileged) or static methods (cannot access private members and can optionally be accessed statically via the prototype of the object)
            //to enforce static vs. instance calls, you can apply an instanceOf check on the "this" object within the function, or have a global EnforceStatic system to handle that step elegantly, but again, for brevity's sake I'll forego that
            instanceIsNameJames: function() {
                return (this.name == "James");
            },

            staticIsNameJim: function(name) {
                return name == "Jim";
            }
        };

        //Now, create a subclass of which inherits from myBase. Inheritance applies to the prototype (static or non-privileged) members as well as to the constructed instance members (meaning I get all public members and parameterized construction of the base class is fully supported)

        mySubclass = Class.create();
        Object.extend(Object.extend(mySubclass.prototype, myBase.prototype), {           //first inherit at the prototype (static) level
            initialize: function(name) {
                //cache the superclass instance to retain access to it's methods
                this.base = new myBase(name);

                //now, inherit the instance members
                Object.extend (this, this.base);

                //handle any method overrides desired now (example code purposely written only to demonstrate overriding with base class preservation)
                Object.extend(this, {
                    sayHiFromJim: function() {
                        if (this.instanceIsNameJames())
                            this.sayHi(true);
                        else
                            this.base.sayHiFromJim ();
                    }.bind(this)
                });
            }
        });

        //base class demo
        new myBase("James").sayHiFromJim();            // "Hi"
        new myBase("Jim").sayHiFromJim();            // "Heyyy, what's up, it's me... you know... you're old pal, Jim Arooney Doony"
        alert(myBase.prototype.staticIsNameJim("Jim"));    // "true"

        //subclass demo
        new mySubclass("James").sayHiFromJim();            // "Heyyy, what's up, it's me... you know... you're old pal, James Arooney Doony"
        new mySubclass("Jim").sayHiFromJim();            // "Heyyy, what's up, it's me... you know... you're old pal, Jim Arooney Doony"
        new mySubclass("Bob").sayHiFromJim();            // "Hi"
        alert(mySubclass.prototype.staticIsNameJim("Jim"));    // "true"


On 7/20/06, Eric Anderson < [EMAIL PROTECTED]> wrote:
Ryan Gahl wrote:
> The beauty though, Eric, is that you can use prototype to achieve this
> as well.

Of course you can do private properties when using prototype. The
support for doing so is provided by closures in the _javascript_ language
so you can do that with any _javascript_ framework. All I was saying is
that the YUI example given (which I am not familiar with) seems to
encourage this behavior. But you can implement it with any framework. I
don't see prototype as helping you with this much. It is just part of
the language (behavior of closures).

> prototype.js into and you'll see it provides the means for a complete
> classical OO style, including private members, interfaces, enums,
> etc..., which greatly (greatly I say) improves code readability, re-use,
> refactorability, concern and behavior separation, etc...

I will have to disagree with you on this point. Although doing private
properties can be done with _javascript_ (using closures) I don't see
prototype as helping you with this any. The code example you gave below
seems quite unreadable to me (no offense, just my opinion of the
readability). Look at the loops that we are jumping through:

> The trick is encapsulating the class definition as a whole inside the
> contructor method (using bind() to preserve the lexical scope of the
> containing class),

Both of these actions seem very unfriendly to me. Having to define my
entire object inside the constructor? Appending a bind(this) to every
method I create? Private properties have questionable value if it is
easy to use. If I have to go through a lot of work the value does not
make up for the increased code complexity in my opinion.

> which adds little to no overhead to instantiation
> since the methods would have to be created in memory anyway...

It will add overhead because each instance of "myObject" will have it's
own property instead of all instances accessing the property through the
prototype chain. Although the difference is so small nobody will know. :)

This also bucks the system because people expect the prototype object to
define common methods instead of each object having it's own reference
to the method. Normally I can do:

myObject.prototype.publicMethod = function() {
     // ... some implementation ...
}

and expect that to redefine "publicMethod" for all instances of myObject
(already instantiated or not). But in this case I am defining the method
in the wrong location because the method is defined inside the
constructor removing the ability to redefine prototype properties.

> Exactly, Eric, and it does so with tremendous success. There are many
> advantages to classical OO, and proto gives you that, plus you always
> have the underlying prototype system of js if you want it (2 OO
> paradigms at your disposal, wonderful!).

I agree that having both systems at your disposal is good. From what I
have heard the "standards people" (whoever they are) are looking to add
real classes to EMCAScript soon (and ActionScript which I believe is
EMCAScript compliant has already done that) so I think many others would
agree both systems are good.

But I disagree that prototype does it will tremendous success. I
consider the class-based OO emulation adequate but not elegant. It was
approaching elegant when "extend" extended Object.prototype but of
course that broke language conventions so it had to be moved to "Object"
which was less elegant. From what I have read Sam Stephenson is not
really happy with the current class-based OO emulation. See:

http://sam.conio.net/

Specifically "Prototype's class system is definitely experiencing
growing pains" and "You can expect Base to make its way into Prototype
2.0 in a form that's backwards-compatible with Class.create and
Object.extend." indicates to me that the current system (Class.create
and Object.extend) is not considered ideal.

I think having some sort of class-based OO emulation is good but I would
hardly call the current implementation a tremendous success. It is
adequate and the rest of prototype/scriptaculous rocks so much that we
still use prototype with enthusiasm. But I think many people will be
happy to get a more elegant system in place.

Just my opinion

Eric

_______________________________________________
Rails-spinoffs mailing list
Rails-spinoffs@lists.rubyonrails.org
http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs

_______________________________________________
Rails-spinoffs mailing list
Rails-spinoffs@lists.rubyonrails.org
http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs

Reply via email to