23

I suppose this could apply to any dynamic language, but the one I'm using is JavaScript. We have a situation where we're writing a couple of controls in JavaScript that need to expose a Send() function which is then called by the page that hosts the JavaScript. We have an array of objects that have this Send function defined so we iterate through the collection and call Send() on each of the objects.

In an OO language, if you wanted to do something similar, you'd have an IControl interface that has a Send() function that must be implemented by each control and then you'd have a collection of IControl implementations that you'd iterate through and call the send method on.

My question is, with JavaScript being a dynamic language, is there any need to define an interface that the controls should inherit from, or is it good enough to just call the Send() function exposed on the controls?

kangax
  • 38,898
  • 13
  • 99
  • 135
lomaxx
  • 113,627
  • 57
  • 144
  • 179

5 Answers5

9

Dynamic languages often encourage Duck Typing, in which methods of the object dictate how it should be used rather than an explicit contract (such as an interface).

John Paulett
  • 15,596
  • 4
  • 45
  • 38
  • 36
    I do not think that interfaces are in contrast with duck typing. Quite the contrary, actually. By declaring an interface, you can have a clear statement of what methods you will try to call. Often I have found methods which accept objects that are, say, file-like, without any clear indication of what a file-like object should implement. Is read() and close() enough? Do I also need seek()? What about write()? Interfaces are a clear and unambiguous way to state your needs, and as such are a big enhancement **especially** if you want to rely on duck typing – Andrea Nov 11 '11 at 17:36
  • 2
    Even the ability to have ad-hoc interfaces that simply declared what methods and members a parameter should have would be useful. It doesn't have to be a named interface - just a value constraint. – B T Oct 05 '12 at 19:16
4

This is the same for PHP; you don't really need interfaces. But they exist for architectural needs. In PHP, you can specify type hints for functions which can be useful.

Second, an interface is a contract. It's a formal contract that all objects from this interface have those functions. Better to ensure that your classes meet those requirements than to remember: "mm, this class has isEnabled() but the other one is checkIfEnabled()". Interfaces help you to standardise. Others working on the derived object don't have to check whether the name is isEnabled or checkIfEnabled (better to let the interpreter catch those problems).

stj
  • 9,037
  • 19
  • 33
Extrakun
  • 19,057
  • 21
  • 82
  • 129
3

Since you can call any method on any object in a dynamic language, I'm not sure how interfaces would come into play in any truly useful way. There are no contracts to enforce because everything is determined at invocation time - an object could even change whether it conforms to a "contract" through its life as methods are added and removed throughout runtime. The call will fail if the object doesn't fulfill a contract or it will fail if it doesn't implement a member - either case is the same for most practical purposes.

Rex M
  • 142,167
  • 33
  • 283
  • 313
  • There is a [knol](http://web.archive.org/web/20120416022026/http://knol.google.com/k/programming-to-the-interface-in-javascript-yes-it-can-be-done-er-i-mean-faked#) (yes knol) on this topic – bobobobo Jan 23 '14 at 02:13
2

We saw a nice implementation in the page below, this is ours (short version of it)

var Interface = function (methods) {
    var self = this;
    self.methods = [];

    for (var i = 0, len = methods.length; i < len; i++) {
        self.methods.push(methods[i]);
    }

    this.implementedBy = function (object) {

        for (var j = 0, methodsLen = self.methods.length; j < methodsLen; j++) {
            var method = self.methods[j];
            if (!object[method] || typeof object[method] !== 'function') {
                return false;
            }
        }
        return true;
    }
};

//Call
var IWorkflow = new Interface(['start', 'getSteps', 'end']);
if (IWorkflow.implementedBy(currentWorkFlow)) {
    currentWorkFlow.start(model);
}

The whole example is at: http://www.javascriptbank.com/how-implement-interfaces-in-javascript.html

Steve Tauber
  • 9,551
  • 5
  • 42
  • 46
0

Another alternative to the interfaces is offered by bob.js:

1. Check if the interface is implemented:

var iFace = { say: function () { }, write: function () { } };  
var obj1 = { say: function() { }, write: function () { }, read: function () { } }; 
var obj2 = { say: function () { }, read: function () { } }; 
console.log('1: ' + bob.obj.canExtractInterface(obj1, iFace)); 
console.log('2: ' + bob.obj.canExtractInterface(obj2, iFace)); 
// Output: 
// 1: true 
// 2: false 

2. Extract interface from the object and still execute the functions properly:

var obj = {  
    msgCount: 0, 
    say: function (msg) { console.log(++this.msgCount + ': ' + msg); }, 
    sum: function (a, b) { console.log(a + b); } 
}; 
var iFace = { say: function () { } }; 
obj = bob.obj.extractInterface(obj, iFace); 
obj.say('Hello!'); 
obj.say('How is your day?'); 
obj.say('Good bye!'); 
// Output: 
// 1: Hello! 
// 2: How is your day? 
// 3: Good bye! 
Tengiz
  • 8,011
  • 30
  • 39