CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Peter's Gekko

public Blog MyNotepad : Imho { }

October 2006 - Posts

  • Pragmatic OOP in JavaScript Part 2 : To prototype or not to prototype

    My recent post on object orientation in JavaScript has resulted in some quite interesting comments. Good fodder for a sequel.

    Prototype

    JavaScript is said to be a language with only objects and no classes. A JavaScript object is constructed using a constructor function. I showed two different ways to set up object members. The official way to do that is using the object's  prototype.

    function ProtoAnimal(named)
    {
        var name = named ? named : 'Unknown';
        this.Name = name;
    }

    function ProtoAnimal.prototype.MakeSound()
    {
        return 'That\'s the ' + this.Name + ' sound' ;
    }

    The problem with functions being part of the prototype is that they can only share data members which are part of the object's public interface, that is this. There is no way to encapsulate data or method members. As an alternative approach I showed a way to introduce members in the constructor function. These members can share private encapsulated data.

    function Animal(named)
    {
        var name = named ? named : 'Unknown';

        this.Name = function()
        {
            return name;
        }

        this.MakeSound = function()
        {
            return 'That\'s the ' + name + ' sound' ;
        }
    }

    Now the name member itself is encapsulated and cannot be changed by a consumer of the object; only read using this.Name().

    The upside of the prototype approach is that all objects instantiated by the same constructor functions share the implementation of the prototype members. This is demonstrated by this code

    function ProtoAnimal.prototype.MakeSound()
    {
        return 'A PROTO BASE sound';
    }

    function ChangedSound()
    {
        return 'A CHANGED sound';
    }

    The consuming code instantiates two ProtoAnimal objects and then sets the prototype's method to the ChangeSound function. (See pt1 how to change method members in JavaScript)

    var myAnimal = new ProtoAnimal('Cat');
    var myAnimal2 = new ProtoAnimal('Dog');

    ProtoAnimal.prototype.MakeSound = ChangedSound;

    text1.value = myAnimal.MakeSound();
    text2.value = myAnimal2.MakeSound();

    You will see that MakeSound on both objects returns the result of the ChangedSound function. To achieve the same result with the encapsulated implementation you have to change the method member of every instantiated object

    var myAnimal = new Animal('Cat');
    var myAnimal2 = new Animal('Dog');

    myAnimal.MakeSound = ChangedSound;
    myAnimal2.MakeSound = ChangedSound;

    text1.value = myAnimal.MakeSound();
    text2.value = myAnimal2.MakeSound();

    So the object's prototype does provide some class-like functionality which can be useful when inheriting. But the downside is still the lack of encapsulation.

    What's the cost ?

    As objects share implementation in their prototype it is most likely that using the prototype would result in far more efficient code. To get an idea of the magnitude I set up a little test. Running script straight from the Windows explorer (Double click a .js file) starts the Windows scripting host. The process is visible in the Windows task manager. You can get an idea of the amount of memory the script is consuming.

    At first sight every non-prototype object has a copy of the MakeSound method; that could get huge. To simulate some real code in there I gave it this (nonsense) implementation.

    function Animal(named)
    {
        var name = named ? named : 'Unknown';

        this.Name = function()
        {
            return name;
        }

        this.MakeSound = function ()
        {
            var moreWaste;
            var moreWaste2;

            /* This is just some nonesense code */
            for (var i= 0; i < this.Name.length; i++)
            {
                var wasted = this.Name.charAt(i);
                if (wasted == 'a')
                {
                    moreWaste = Math.exp(i);
                }
    `        }
            for (var j= 10; j > this.Name.length; j--)
            {
                var wasted2 = this.Name.charAt(j);
                if (wasted == 'z')
                {
                    moreWaste2 = i + Math.Random;
                }
            }
            /* End of nonesense code
                    just another comment */

            return 'That\'s the ' + name + ' sound\n' + moreWaste + '\n' + moreWaste2;
        }
    }

    The ProtoAnimal's MakeSound method got the same treatment.

    The script to test memory usage and constructing speed

    var WSHShell = WScript.CreateObject("WScript.Shell");
    var zooSize = 200;
    var zoo = new Array();

    WSHShell.Popup('Ready ?');

    var start = new Date();
    for (var i = 0; i < zooSize; i++)
    {
        zooIdea = new ProtoAnimal("Alive " + i);
    }

    var constructTime = new Date() - start;
    WSHShell.Popup('No of objects ' + (zooSize) + '\nTime to build ' + constructTime + ' ms');

    The popup's provide the moment to check memory usage. I ran the test for 2 to 200000 objects. It is a wet finger (as the Dutch saying goes) but nevertheless some results.

    • It takes creating 2000 objects to get some real results (the curve pf object count vs memory becomes straight)
    • It just takes one second (P4 2.6 Ghz) to construct over 30000 objects
    • The non-prototype objects take 50% longer to construct
    • Creating 200000 animals costs 300 Mb, 200000 proto-animals still cost 150 Mb.
    • Using prototype objects takes half the amount of memory. Also at lower numbers. This was found to be linear in the range of 2000 objects or more.

    Especially the linear behavior gives the impression that a prototype is not as simple as it looks. Overall the tests show that it is more efficient to use the prototype but the results (imho) no way prohibits working the encapsulated way. It is a balance between better code and performance metrics. These days the latter is, thank goodness, not always the leading. You don't have to chose between the two. Only a member which needs private members has to be part of the constructor function, all others can be part of the prototype.

    Inheritance revisited

    This is real inheritance as seen in C#

        class MyBaseClass

        {

            internal virtual bool MyFunction(int i)

            {

                return i > 0;

            }

        }

     

        class MyInheritingClass : MyBaseClass

        {

            internal override bool MyFunction(int i)

            {

                bool isOk = base.MyFunction(i);

                if (isOk)

                {

                    isOk = i > 10;

                }

                return isOk;

            }

        }

    The inheriting class overrides MyFunction. When implementing the implementation in the baseclass is still available.

    JavaScript simulates inheritance. We have seen it is no problem at all to assign a new implementation to a function. But that will overwrite the original implementation, there is no such thing as base.MyFunction. What most of JavaScript's inheritance implementations do is copy the members of the prototype from the base to the inheriting class. Libraries such as discussed here have almost all inheritance features as found in a true OOP language available. Doing so they introduce ways of coding which may raise an eyebrow when you're used to C#. And still they bypass encapsulation.

    Looking at the core of the problem there is only one thing which counts: the constructor function returns an object; that object has members. Which members there are depends on the prototype of the constructor function and the constructor function itself. In my previous post I showed a constructor which republished the members of an aggregated base object.

    function Cat()
    {
        var base = new Animal('Cat');

        this.Name = base.Name;
        this.MakeSound = function()
        {
            alert('Mew');
            return base.MakeSound();
        }
    }

    I would like to add an alternative implementation, a variation on one suggested by Jeremy

    function Cat()
    {
        var base = new Animal('Cat');
        var MakeSound2 = base.MakeSound;

        base.MakeSound = function()
        {
            alert('Mew');
            return MakeSound2();
        }

        return base;
    }

    The main difference is that this constructor function explicitly returns the aggregated base object. By default a constructor implicitly returns this. This constructor also shows that JavaScript does not understand two implementations of a member, the base one and the overridden one. The base MakeSound method has to be copied to MakeSound2, else it would be lost when creating the overridden implementation. Using this way to simulate inheritance I don't have to re-publish all members of the base class but I end with having to store the base implementation myself.

    To conclude

    I don't want to jump to conclusions; I can only advise you to be pragmatic. The main problem with JavaScript is that it can so much. With lots and lots of possibilities to really screw up your code or create something nobody will understand. Not even yourself when revisiting your own creation over time. I do hope to have you provided with enough possibilities to satisfy both your performance and clarity-of-code needs. 

  • Pragmatic OOP in JavaScript

    JavaScript is the only language a web browser speaks; it is a given fact. It's not a matter of choice if you are going to work with it, whenever you build a browser app it is there. All script code might be hidden to you but there is no ASP.NET, let alone Atlas (AJAX) without JavaScript. Recently I've been doing a project which involved loads and loads of JavaScript. Being a C# addict myself I had to get used to it but quite soon I found it had more power than I believed at first. The first thing I wanted to know about my new programming environment is how it supports OOP. When browsing for information on JavaScript and OOP the problem seems to be that two disciplines have such a different background. The majority of JS is produced by web-designers who have to write some code to get their site working. The majority of OOP information is provided by "real" programmers who look down on JS. And there are people like Douglas Crockford to whom JavaScript is the language where almost every way of programming meets. I don't share his enthusiasm but his site is a must read and did provide me the best basis for workable patterns. As promised here is my, C# based, way of OOP in JavaScript.

    Getting started with JavaScript

    Getting started is no big deal. At first sight you just start typing ahead pretending to write in C#. But there is no compiler or unit testing to validate your work; not until the code is interpreted at run time. As you can do horrible things in JavaScript it does take a lot of discipline to write good code. Also because the language itself is not as strict as C#. The following snippet of code will run

    function CheckId()
    {
        if (text1.value != "")
        {
            Id = ++text1.value;
        }
        else
        {
            id = -1;
        }
        return id;
    }

    An undeclared variables is created on the fly with global visibility. In this case two, Id and id, are introduced. All script code on the webpage will see an Id a an id variable (the different casing is a typing error). As JavaScript is case-sensitive these are two distinct members. Both will keep their value over calls to the function. But this id does not make much sense outside of the function.

    You limit the visibility of a member using the var keyword. This code does the same without any of the side effects.

    function CheckId2()
    {
        var id = -1;
        if (text1.value != "")
            id = ++text1.value;
        return id;
    }

    Note that variables and functions in JS do not have a type. The value of the function result or the variable's values is formed by the context. Which can lead to confusing things. These three expressions are all true

    1 + 2 == 3;
    1 + '2' == '12';
    1 + '2' ==  12;

    The last one looks funny at first sight. But it makes sense when a ToString() is applied first to every member of the expression.

    Objects in JavaScript

    In C# an object is described by the class it's instantiated from. The class is the type of the object. We just saw that the JavaScript language does not have types. Objects in JS are created by a constructor function. An object in JS is a dynamic collection of variables and functions. All methods in JavaScript are functions, a procedure is in JS a function without a return statement. The constructor function below creates a new object with a Name and a Counter member.

    function MyObject()
    {
        this.Name = 'A Javascript object';
        this.Counter = 0;
    }

    The this keyword marks the members as public accessible. You instantiate an object using the new keyword.

    <script>
        var myObj = new MyObject();
        function CountOnMyObject()
        {
            text1.value = myObj.Name + ' ' + (++myObj.Counter);
        }
    </script>
    <input type="text" size=90 id ="text1" />
    <input type="button" value = "Debug" onclick="CountOnMyObject()">
     

    When the page is loaded the new object is created. On every click of the button the count is raised and the object returns it's name and count. Here we have the base of object orientation, the possibility to bundle data and functionality at work.

    There are several ways to add methods to the objects. What you will find most is a declaration which adds a function to the so called prototype of the object. These functions can access the other members of the object..

    function MyObject()
    {
        this.Name = 'A Javascript object';
        this.Counter = 0;
    }

    function MyObject.prototype.DoubleCount()
    {
        return this.Counter * 2;
    }

    The DoubleCount() function returns twice the current value of the Counter member.

    As said, JavaScript objects are a dynamic collection of members. These members can be variables or functions. Any piece of code can add a member on the fly. This can be done inside an existing member of the object.

    function MyObject.prototype.DoubleCount()
    {
        this.OnTheFlyMember = 'Set';
        return this.Counter * 2;
    }

    The result is that myObj.OnTheFlyMember is undefined until the first time myObj.DoubleCount() is called.

    But it can even get greasier than that. Also a snippet of script consuming the object can add a member on the fly

    <script>
        var myObj = new MyObject();
        function AddMemberToMyObject()
        {
            myObj.MemberFromScript = 'Hello from a snippet of script';
        }
    </script>
     

    We will see later the not just member variables but also member functions can be added or altered. To some people this dynamic nature of JavaScript is a bliss which opens the doors to great ways of programming. I'm not sure about that, there are other languages in case I would dive into that. Me and other mortals just need plain simple, maintainable and easy to understand code. Object orientation is a step towards that but the OO we have seen so far is no more than a bundling of variables and functions with a public visibility.

    <Update>Part 2 further discusses prototype</update> 

    What makes objects far easier to work with is encapsulation. Not just hiding the implementation of the method but also hiding all internal data inside the object and all helper methods without any relevance to the object's consumer. An object should only expose those members which are of relevance to the consumer. This is done in JavaScript using a slightly different syntax.

    Now all functions are defined in the constructor function.

    function MyObject()
    {
        var name = 'A Javascript object';
        var counter = 0;

        this.Count = function()
        {
            counter++;
        }

        this.Name = function()
        {
            return name + ' with a count of ' + counter;
        }
    }

    Using the var keyword the name and counter's visibility are limited to the constructor function. As the exposed members this.Count and this.Name are also declared inside the constructor function they can reach the private vars. They are named privileged members. The members declared on the prototype are named public. To the script consuming the objects there is no difference except when it comes to working with the prototype, something we will meet when taking a look at inheritance. The object exposes public and privileged methods and encapsulates the private vars.

    Also a helper method can be a private member. It is used by the object's members but is not visible by the object's consumer.

    function MyObject()
    {
        var name = 'A Javascript object';
        var counter = 0;

        function capFirst(aString)
        {
            var str1 = aString.substr(0,1);
            var str2 = aString.substr(1);
            return str1.toUpperCase() + str2.toLowerCase();
        }

        this.Count = function()
        {
            counter++;
        }

        this.Name = function()
        {
            return capFirst(name + ' with a count of ' + counter);
        }

        this.AnotherName = function(anotherString)
        {
            return name + ' ' + capFirst(anotherString);
        }

    }

    Now we have objects which can hide data and implementation and expose just that what is of interest to the consumer. Just like the .net object you're used to.

    Methods, overloads and properties

    In a language like C# you have overloads, that is multiple versions of a method each with a distinct parameter list. There is no such thing in JavaScript. The function with a matching name is called passing it all parameters. Even when the parameters are not specified in the function declaration they are available in the function's implementation via the arguments keyword. This AnotherName method declares only 1 parameter.

    function MyObject()
    {
        this.AnotherName = function(anotherString)
        {
            return arguments.length;
        }
    }

    When you use it with a longer parameter list, like this:

    text1.value =myObj.AnotherName(text2.value, 'Boe', 'Blub', 9);

    the AnotherName method will still be hit and it will return 4 . You can use something like overloads in JavaScript but all implementation has to be done within one method. It has to inspect the number and content of the arguments actually passed and act accordingly.

    To have the kind of object you're used to, where methods can reach private data, requires privileged members. What the JavaScript syntax in such a declaration actually does is assign a function variable to a member of the object

    this.MemberName = function(params)

    This dynamic way JS mixes code and data can hit back when you look at properties. The constructor function below initiates a property Name and a privileged method AnotherName.

    function MyObject()
    {
        this.Name = 'A Javascript object';

        this.AnotherName = function(anotherString)
        {
            return 'Another ' + anotherString;
        }
    }

    The consumer can read and set the Name property and call the AnotherName method.

    text1.value = myObj.Name;
    text2.value = myObj.AnotherName(text2.value);
    text3.value = myObj.AnotherName;

    The third statement is also valid. The object has besides the method AnotherName() also a  property AnotherName (without parenthesis). The property will return the implementation of the AnotherName method. The first time you meet this, for instance when you forget the parenthesis in a method call it will make you scratch your head. The bad thing is that you can also set this method property from code. Needless to say that this is the way to have your carefully crafted code wrecked by consuming code. Or altered, which is a next subject.

    Static members

    A static member is a member which is available without first creating an object instance. JavaScript does have static members. They are declared outside of the constructor function.

    function MyObject()
    {
        this.Name = 'A Javascript object';
    }

    MyObject.MyStaticProp = 'This is a static property';

    function MyObject.MyStaticFunction()
    {
        return 'This is a static function';
    }

    You use them in your code by using the constructor function's name as a prefix.

    text2.value = MyObject.MyStaticFunction();

    The usability of static members is limited as they cannot be used by the privileged members. But they are a nice way to organize a bunch of related functions into a class.

    Inheritance

    Inheritance is the weak spot in JavaScript's OOP implementation. The language itself does not include the idea. Scattered over the web you will find a wide variety of hacks to implement it. Harry Fuecks tries to give an overview and does provide an, at first sight, elegant solution himself. The main problem with all the implementations, including his, is that they work with the prototype and thus only work for public members. The big problem we just saw with public members is that they cannot work with encapsulated private members. The way to keep your objects clean is using privileged members, that was having all code in the constructor function. The implementations found on the web don't work with these privileged members.

    A reason for inheriting from a base class is polymorphism, where you pass an object of a derived class to code expecting an object of the base class. As JavaScript just tries at runtime if the object has a member with a matching name, polymorphism will always work as intended. Another reason for inheritance is changing the behavior by overriding members. We have seen that you can add or replace any member of a JavaScript object on the fly. Instead of inheriting you can aggregate an object, using a base class to implement things. Take these creatures

    function Animal(named)
    {
        var name = named ? named : 'Unknown';
        this.Name = function()
        {
            return name;
        }

        this.MakeSound = function()
        {
            return 'That\'s the ' + name + ' sound';
        }
    }

    function Cat()
    {
        var base = new Animal('Cat');

        this.Name = base.Name;
        this.MakeSound = function()
        {
            alert('Mew');
            return base.MakeSound();
        }
    }

    The Animal constructor function provides an object with basic functionality. The Cat constructor creates an Animal object, passing in a value for the name. The Cat constructor exposes the animal's Name function and provides an own implementation of the MakeSound function which augments the base implementation.

    <Update>Part2 discusses a variation</update> 

    Most hacks on the web are able to publish all public methods in one go using the prototype. I have to explicitly re-publish every privileged member. But the members of my object can keep working with shared private var's; provided the members are in the same class, the Cat constructor cannot see the Animal name var. I need some extra lines but this is a price I'm quite willing to pay for a better encapsulation.

    Conclusion

    The four tenants of OOP programming are abstraction, encapsulation, inheritance and polymorphism. Judging JavaScript on each of them

    • Abstraction is met. The object consumer only sees published members, not the implementation.
    • Encapsulation is met. Not only the code but also private data can be hidden from the object consumer
    • Inheritance is not met, but thanks to JavaScript objects being dynamic a simple and pragmatic work-around is possible
    • Polymorphism is in the core of the language.

    The main point of JavaScript to me is being able to work with it in a pragmatic manner and have simple well structured code. Which is possible as long as I restrict myself.

     

  • A small "Designed for Windows mobile" rant

    As you perhaps know I have a weak spot for mobile development. For a project I recently dug through the "Designed for Windows Mobile" logo specifications. This logo is meant as a certification that the app will run on any mobile device. One of the logo requirements is that the app will adapt to the screen real estate available. The first generation of devices were all 240 by 320; these days smaller square screen as well as a full size VGA ones are abundant. To make sure your app will handle these smaller or bigger sizes is, using the compact framework, no big deal.

    Being interested in mobile I also read the MS Mobile newsletter. Last issue offered some quite appealing downloads. Space-invaders for my iPaq as well as a lite version of 1-calc. The most interesting part of the latter are endless conversions; living in the metric Europe it would be a great help to understand foreign metrics. Now here is the rant: Both applications don't carry the logo and would never get one. They are hard coded to a 240*320 screen size and don't display right on my 240*240 mobile messenger. I can see the aliens coming but I can't fire back. The calc application uses hard coded skins. The trial version of the full product includes (and installs) a square skin; the free version does not. Even when the skin fits the soft keyboard gets in the way and some of the dialogs are completely clipped.

    It would have been so nice if MS took their own logo serious and either use it to convince software publishers to comply or use it to select something less frustrating. The apps look great but they just don't work for me.

  • Tidbits (Javascript and OOP ?)

    For the past few weeks I've been working fulltime on a big Javascript application. At first this did not look like any source for blog fodder at all. Having learned lots of new things I have changed my mind and am working on a big post on Object Oriented Programming in JavaScript. What is possible and what is not. Information on the web varies in a high degree. Feel free to make suggestions on what I should include and what not.

    It's not going to be a rant on why JavaScript sucks, I can't agree on that. It's not going to be a big praise on the language either, script remains script. JavaScript is just there, you cannot ignore it; better just make the best out of it.

    Two Dutch tidbits in the last  weeks:

    • After supporting the Frisian language, the Vista RC does include a (tablet) handwriting recognizer for Dutch! At last ! Saw it at work today on the MS Technet meeting. The default language of my OS is English. I'll look into installing multiple recognition languages and will come back on it.
    • My slightly deformed article in the Dutch .NET magazine has been reformatted and is available online here.
More Posts