Search code examples
javascriptnode.jsinheritanceinstanceprototypal-inheritance

Implementing Interfaces in NodeJS


The NodeJS Documentation states:

"The request object is an instance of IncomingMessage. The request object that's passed in to a handler implements the ReadableStream interface"

"So far we haven't touched on the response object at all, which is an instance of ServerResponse, which is a WritableStream."

JS has Prototypal Inheritance so when the documentation says it is an instance it means it adds to the prototype chain, but how it implements an Interface in JS?

And how is this all chained up and how it works. The Official NodeJS Documentation does not explain.

Source - Anatomy of an HTTP Transaction

Edit- My Question is not related to multiple Inheritance in JS. It is about how NodeJS modules implements interface which is natively not supported in JS. I beg your Pardon if there is any mistake in my question or lacking in my knowledge. Thanks!


Solution

  • Interface = Obligation.

    To implement an interface = Provide members which are expected by these who call you.

    What the docs say about this particular interface, the ReadableStream?

    Well, here it says

    All Readable streams implement the interface defined by the stream.Readable class

    And what is the stream.Readable?

    Well, here a complete "interface" is provided and it consists of multiple members, including read, pipe and others.

    Technically, in JS there are multiple ways of "implementing" such obligation:

    • an easy way is to set an object that already implements the interface in the prototype chain of an object that is supposed to implement the interface. This way all interface members are delegated (by means of the proto chain) to the other object

    • a more direct way is just to provide all necessary members directly by the object that is supposed to implement the interface

    • a hybrid approach where some members are delegated down the proto chain, some members are implemented directly and some members are delegated to other objects by direct invocation

    Because of the nature of the language, the caller which expect the interface to be implemented will accept all these possibilities.

    E.g. The docs says the interface contains a method

    foo(n)
    where n is a number 
    returns a number
    

    You have following options.

    Option 1, a direct implementation

    var o = {
        foo: function(n) {
           return 0;
        }
    }
    

    Option 2, delegation down the proto chain

    // an object that already implements the interface
    // i.e. has function foo(n)
    var existing = ....; 
    
    var o = Object.create(existing);
    
    // o has function foo though its proto
    

    Option 3, delegation by invocation

    // an object that already implements the interface
    // i.e. has function foo(n)
    var existing = ....; 
    
    var o = {
       foo: function(n) {
           return existing(n);
       }
    }
    

    All these options can possibly be expressed with construction functions, too.