Nonsense

This time I was asked about JS prototypes, polymorphism…

I'm trying to learn more about prototypes in js. I know how to create a function for a defined prototype. How would I create a new prototype / object? I know from there, I could then make a new instance with the new keyword.

I've been reading eloquent js and I like the book, but find the section on objects confusing.

I really like how you explain things and I was wondering if you could explain polymorphism and interfaces for me, if you don't mind?

My answer was really, really long… and boring, of course. It was so long (and so boring) I had to split in into two or three parts. I'll insert a couple of additional questions that came up along the way.


Ok, I see… Yes, in the summary of chapter 6 (of Eloquent JS) and when speaking about polymorphism. The thing there is that Haverbeke is talking about the idea of interfaces, the concept, but not the “interface entity” as in Java or C#. I'll try to explain what he means there at some point.

I may break all this into two or three messages.

So… First a very quick introduction to creating objects. I may omit some details here, but if you miss something just ask :)

Creating objects and this

In Javascript you have two main ways to create an object. The first one is just using literal notation:

    var someObject = {
        someproperty: 1,
        another: "one"
    };

This is all fine for one-off objects. You create one and that's it. There's no more to it. The second way is through a generator function and the operator new. Now, a generator function (or constructor function, you'll probably see more that name being used) is actually any function. I mean, even this…

    function nothing() { };

…can be used as a constructor. It doesn't generally make much sense, but it can. How would we use it to create an object? With the new operator. We do…

    var oneOfNothing = new nothing();

…and we have an object. It's important to know at this point how this works, because it will come into play at various points. So let's see what happens.

  1. First, the new operator is the one that actually creates the new object. The name says it all :) I'll come back to this precise moment when talking about prototypes, so remember it. But for now, it is enough to know that new will also set some internal properties on the new object.
  2. The new operator calls the nothing function setting that newly created object as thisValue.
  3. nothing runs. (In a moment we'll see a better example)
  4. new returns the newly created object and it is then assigned to oneOfNothing in this example.

With a better example, like…

    function Sound(url, bitrate, encoding) {
        this.url = url;
        this.bitrate = bitrate;
        this.encoding = encoding;
    }
    var shout = new Sound('http://soundbible.com/grab.php?id=1627&type=mp3', 128, 'mp3');

…point 2 will make a bit more sense. In some sort of pseudocode, new could be thought as something like this:

  operator new(f, args) {
      // create a new empty object
      var newObject = {};
      // set some internal properties:
      setInternalProperties(newObject);
      // call the original function with newObject as this value (and the rest of the arguments):
      f.applyl(newObject, args);
      // return the newly created object
      return newObject;
  }

So the Sound example would be something like…

  1. create an emptyNewObject {} and set some internal properties on it.
  2. Sound.apply(emptyNewObject, ['http…', 128, 'mp3'])
    1. Sound executes with this pointing to the emptyNewObject
    2. emptyNewObject.url = 'http…', emptyNewObject.bitrate = 128, emptyNewObject.encoding = 'mp3'
  3. return emptyNewObject (which now is not empty any more ;) )
  4. assign it to shout

So in the end…

  shout <--> {url: 'http...', bitrate: 128, encoding: 'mp3' }

(Note: The real new operator does something else that I've not mentioned with regards of the final part of the process… a more real life pseudocode would be something like this…

  ...
  var returnedByFunction = f.apply(newObject,args);
  if (returnedByFunction is an object) return returnedByFunction;
  else return newObject;

…but you can safely ignore that for our purposes. It's not really something you generally have to keep in mind except for very particular circumstances)

So, new is just that. Nothing more to it. That setInternalProperties(newObject) is what actually matters most in all this. But before we can talk about it, we need to know about prototypes. Also note that there exists Object.create which is a newer way to create objects. I haven't mentioned it because it's better to talk about new and prototypes first.

Prototypes

In Javascript every object has an internal [[Prototype]] property. Internal properties are there for the JS engine to make some features of the language work as they should. The [[Prototype]] property is there to implement the idea of “prototypes” and the “prototype chain”.

What is a prototype?

To be clear: a prototype is just an object, any object. So the [[Prototype]] property is simply a reference to some other object. That other object, also subject to what I said about “every object has an internal [[Prototype]] property” will in turn have another prototype which will be another object which will then have a prototype… until the “last one” which will have null as a prototype and things end there.

And so this is referenced as the prototype chain.

Right now this may sound somewhat confusing, but that's just because we haven't seen what all this is for, why we want this. Right now, simply think about this:

In a “class-based language” such as Java or C#, you have something close to this. In those languages, you establish a hierarchy of classes. Golden extends Dog which extends Mammal which extends LivingThing. You then instantiate baxter as a new Golden()

    Golden baxter = new Golden();

…and a similar chain exists. The difference is that in those languages the relationships are defined among classes. In Javascript, the prototype chain is a relationship that is defined between objects.

What the prototype chain is for

The prototype chain is used to implement the same idea of inheritance you can find in class-based languages. It works differently, but the underlying goal is the same: We want to define some property (or method) in an object and be able to share it or be available on some other objects.

How does the prototype chain achieve this

This is easy. Let's say we somehow (don't worry about how yet) have some prototype chain set up between objects A, B, C and D.

  A -> B -> C -> D -> null

The way the prototype chain works is this: Whenever I try to access A.colour the engine looks up the property in object A. If it's found there, great, all is done. But if not, the JS engine gets A.prototype (which is B) and looks up the property there, B.colour. If it's found there, great, all is done. But if not, it gets B.prototype (C) and looks up C.colour… you get the idea. This continues until the last one which has prototype null. If it hasn't been found anywhere in the chain by this time, an error occurs.

Now imagine… Imagine a lot of different objects A1, A2, A3A100 and they all have B as prototype. Then a property set on B is in some way shared or available to all An objects.

new and the prototype chain

Right, so remember that line of pseudocode I said we would come back to? I said…

I'll come back to this precise moment when talking about prototypes, so remember it. But for now, it is enough to know that new will also set some internal properties on the new object.

So, this is where it all comes together. Actually, what new does in that line I wrote as setInternalProperties(newObject); is precisely setting the internal [[Prototype]] property of newObject. Oh, first a very short bit about notation.

I sometimes write [[Prototype]]. That's the internal property, it's called like that, with the double brackets and all. Other times I simply say the prototype. That's the concept in itself. Other times, you will see in code somefunction.prototype.blabla. That is the external property, the property that is visible for us as programmers. It's relevant to know that only functions have this external property, other objects do not. (More on this later)

So, on with new and the prototype. We can now expand our pseudocode for new…

  operator new(f, args) {
      var newObject = {};
  
      // set some internal properties:
      // ...
      newObject.[[Prototype]] = f.prototype; // remember this is pseudocode; [[Prototype]] is internal.
      // ...
  
      f.apply(newObject, args);
      return newObject;
  }

So doing var shout = new Sound(…) sets shout's prototype pointing to Sound.prototype. Each object we create as new Sound(…) gets Sound.prototype as its prototype. With this in mind and what we talked about earlier, if we did something like this…

    function Sound(...) {
        // same we had before
    }
    Sound.prototype.play = function() {
        // play the sound
    }
    Sound.prototype.stop = function() {
        // stop the sound
    }

…all objects we create as…

    var shout = new Sound('http...', 128, 'mp3');
    var blast = new Sound('http...', 96, 'ogg');
    var shot = new Sound('http...', 320, 'mp3');

…they would all have their prototypes set up as Sound.prototype. So, we can then try…

    blast.play();

Now, the object blast does not have a play method. So the engine goes up to blast's prototype and looks there. blast's prototype is Sound.prototype which does have a play method, so the engine executes it. This happens for blast, shout, shot or any other new Sounds we create. They all share the same prototype which is Sound.prototype so anything we add to that one is available to all of the created objects.

A couple of fine details

There are a couple of details we must address.

shadowing

When we try to read someObject.someProperty we already know how it goes up the prototype chain and all that until it finds such a property (or errors out). There are 2 details to keep in mind. One is, once it finds someProperty it gets that one and stops, does not go further up in the chain. This is called “shadowing”, meaning that if an object has a property someProperty in the middle of the prototype chain it may shadow other objects further up which could also have a someProperty. The other detail is that this works for reading, for looking up a property (or method). But assignment happens on the object itself. This is obvious, but important to be aware of.

If we did…

    blast.play = function() {
        // do nothing
    };

…we wouldn't overwrite the play method in Sound.prototype. All other objects would still see Sound.prototype.play, but blast.play would shadow that with the local method only for blast.

Object.create() and Object.getPrototypeOf and __proto__

__proto__ is something you can safely ignore. It was never standard and it's set to disappear. In any case, what it was… remember I said objects other than functions did not have the external property prototype? Well, at some point in the past someone decided it would be a good idea to have it. That is what __proto__ is. It's the same as prototype on functions but for other objects.

What has been introduced as standard to do the same as __proto__ is not a property but the method Object.getPrototypeOf(someObject). It gets you the prototype of someObject. Useful? Not generally useful. Just in some particular circumstances for people creating particular libraries.

Also introduced more or less recently is Object.create() which let's you avoid using new. I have never seen too much need for it, but in a couple of corner cases it may be useful. Object.create lets you create objects setting the prototype in an explicit manner and that prototype may be any object.

Bigger prototype chains

Ok, back to prototype chains for a bit more.

As we have already said prototype chains will let you set up some sort of inheritance. In the previous example the chain was small. Just…

  blast -> Sound.prototype -> Object -> null

(Uh, yes, I may have forgotten to tell you. Not terribly important, but everything has Object at the end of their prototype chain. Object is like the god object all others inherit from)

But in a bigger application you may be faced with the idea of setting up a bigger hierarchy. Maybe you could have something like… Sound, BackgroundSound and ForegroundSound, and ForegroundSounds could be… whatever CriticalFGSound and SecondaryFGSound (I'm just making it all up xD).

Before showing you how to set something like this up, a small warning: While class-based languages may be more adapted to create big hierarchies, in general JS way of doing things is not really intended for that. I don't mean to say don't do it, but it is better to think about other ways of structuring things than to make a big hierarchy.

Anyway, what you would do to do all this is something like…

    function Sound() { ... }
    Sound.prototype.play = function() { ... };
    
    function BackgroundSound() { ... }
    BackgroundSound.prototype = new Sound();
    BackgroundSound.prototype.whatever = function() { ... };
    
    function ForegroundSound() { ... }
    ForegroundSound.prototype = new Sound(); // [1]
    ForegroundSound.prototype.somethingElse = function() { ... };
    
    function CriticalFGSound() { ... }
    CriticalFGSound.prototype = new ForegroundSound();
    
    function SecondaryFGSound() { ... }
    SecondaryFGSound.prototype = new ForegroundSound(); // [2]
    SecondaryFGSound.prototype.play = function() { /* only play if no critical sound is playing */ };

The line with // [1] what it does is create a new Sound (which would then have Sound.prototype as prototype), and set it as ForegroundSound's prototype. (The same thing is done for BackgroundSound). So, what happens if we then create…

    var shot = new ForegroundSound(...);

We would get this prototype chain:

  shot -> ForegroundSound.prototype (which is a Sound object) -> Sound.prototype -> Object -> null

With a var blast = new CriticalFGSound(…) we would get one like this:

  blast -> CriticalFGSound.prototype (is a ForegroundSound object) -> ForegroundSound.prototype -> Sound.prototype -> Object -> null

At this point I was asked…

I think the main question I have from this, and this may be answered in your later messages, is why and when would I create a custom object? And, a confirmation, polymorphism— isn't it when an object shares some properties of another object. For example, I could create a Month object that extends the predefined Date or a abbreviation object that extends string, right? How would I go about doing that, though ( I would define the new object in the constructor function, but then how do I extend string; for example, and all it's functions and properties to this new object? )

I answered first the question on polymorphism and then continued…


Very briefly, no. Sharing properties is actually inheritance. Polymorphism's goal is that given some hierarchy like the one with your Date and Month, you want to be able to make some function which can operate equally on either Dates or Months without caring which is it. But don't worry, I'll expand this explanation tomorrow.

Polymorphism, duck typing, and interfaces

Ok, so… OOP has these concepts it uses. Very very briefly:

Encapsulation is about grouping things that go together. Instead of having an x variable and a y variable you build a Point object with x and y properties. Inheritance is about sharing properties (and methods) across objects. We already saw that. Now, polymorphism is about the shape of objects, it is about being able to use similar objects in a similar way.

I'll try to explain better, but in JS polymorphism is quite simple.

A Robot is a Machine

Let's imagine we're building an application to control our secret laboratory. We have all sorts of Machines, such as Robots, MillingMachines, and FlyingDrones. Even an AdvancedAndroid. Something all our inventions have in common is they have an activate method to turn them on.

How we've programmed all that is not important. I mean, maybe Machine has the activate method and all others inherit it. Or maybe some of them a different activate method. The problem at hand at this moment is we want to implement an EverybodyOn method to our Laboratory object.

    var allTheStuff = [ LaserCutter, SecurityBot, ... ]; // an array with all our machines
    var Laboratory = {
        everybodyOn: function() {
            // activate each one of them
        }
    }

Now, in a language like Java or C# with classes and static typing, if we tried to do something like this (pseudocode)…

  for (machine in allTheStuff) machine.activate();

…the compiler would, when trying to compile, check if all of our objects are of the appropriate type. If not, it would give an error and refuse to compile. The way it does that is actually check for the type, the class we are using. We would actually have something with types…

  Machine[] allTheStuff = ...;

…so it would say: “Aha, these are all Machines. Does the class Machine have an activate method?” and that's how it would see if it can compile or not.

In Javascript it is simpler. Well, it's dynamically typed and there's no compiling, so it has to be simpler. What the engine does is simply this: “Does this particular object here have an activate method now?” If it has, it just calls it. If not it gives an error. You may sometimes see this called duck typing, following the old saying “If it quacks like a duck and swims like a duck, it must be a duck”. But we actually don't care if it is a duck or not, we just need to know if it quacks and swims. But in any case, that's what they call it, so you may see the term “duck typing” around.

Now, what is polymorphism? Well, it's just that, the ability to treat different but similar objects in the same way. We have all sorts of different objects, generic Machines, Robots, MillingMachines… For each of them activate may do different things, the MillingMachine may load a default cutter head, the Robot may have to check all its sensors, the FlyingDrone may fly to a certain position… But from the perspective of our EverybodyOn method, for us it's just activate for all of them. That is polymorphism.

There's nothing more to it, but I'll add a small detail about JS. As I said, JS doesn't check types, just tries “Does it have this method?” and that's enough. In fact, I could have things which aren't even machines. I could have an EmergencyPlan which could have an activate method.

Interfaces

Interfaces are also about the shape of objects and are related to polymorphism. In Java or C# “implementing an interface” is a kind of contract. You state that your class has some particular methods. “Robot implements Activable” is the promise that your Robot class has some activate method.

In Javascript, the language does not give you such a mechanism. There are several reasons for this, but the main one is that having “duck typing” sort of defeats the purpose of interfaces. In fact, the contract given by interfaces is needed mostly for the type checks the compiler does, but in JS there's no such thing. If this thing has an activate method I can call it. If not, well, it will error.

Now, when “Eloquent Javascript” talks about interfaces, it is referring to something a bit more general. An interface is also “the part of something we can interact with”. This is applicable to almost everything. The interface of a TV is the on button, change channel button and volume up/down buttons. The interface of a hammer is its handle. The interface of a person could be something like his/her senses (voice, hearing, vision, smell, touch…). When talking about an object's interface, what Haverbeke means is just that: the design of which methods and properties the object has to let us interact with it.

The hard question

why and when would I create a custom object?

That's actually a hard question. Not very hard, but somewhat hard. The reason for that is that this question goes a bit further. It is a question about program design, about structure and architecture. I'll try to give a satisfactory answer, but… my main feeling about these topics tends to be “experience will tell you”.

Anyway, the reasons for creating your own objects are many. Their importance is subjective and may vary depending on the circumstances. I'll give you some.

To me, encapsulation is certainly one of the most important ones. Encapsulation means order, structure and cleanliness. If some variables are very closely related, it makes much sense to group them together. Think about the Point example before. You could of course have a bunch of x coordinates and y coordinates in separate variables x1, y1, x2, y2, x3, y3… But what if you had a hundred? It gets messy pretty quickly. You could of course just use arrays. Maybe…

    var xs = [ ... ];
    var ys = [ ... ];

But it doesn't (usually) make sense having x and y coordinates separated. So you might use arrays in another way…

    var points = [ [0,0], [0,1], ... ];

…and in some situations this will be perfectly enough. Really, that's not a bad solution per se. But you could also go a bit further. You may want to have a Point object which not only encapsulates coordinates, but maybe also colour, or some other values associated with it…

    function Point(x, y, colour, numberOfOccurrences) {
        this.x = x;
        this.y = y;
        this.colour = colour;
        this.numberOfOccurrences = numberOfOccurrences;
    }

…or maybe even some methods which work only on Points, like plot or move.

Again, you could certainly structure your code in different ways, but one important reason to create custom objects is keeping things in some order, and maintaining your code clean and well structured is surely one of the best goals you can pursue. Encapsulation and order also avoids problems like name collision (if everything was a global function or variable instead of methods and properties on objects, all names would have to be different).

Other reasons, such as all we've seen about inheritance, are also important, of course. It all adds up. But in the end it's all about the basic principles of grouping stuff together, ordering stuff cleanly and avoiding repetition.


There were a couple of additional questions that came up from this.