Friday, March 01, 2013

Correction: Javascript NOT more dynamic than Python

EDITED: Adam showed me that I had missed a way to do something similar in Python as I added below.
====


After a very long hiatus, I'm finally back and working on a web version of rur-ple, my "Karel the Robot in Python" program.  Since it's going to be on the web, I have decided to have both a Javascript version and a Python version (using Brython).  As I was exploring javascript prototype-based "inheritance" pattern, I found  what I think is a neat way to illustrate how dynamic the method lookup can be in Javascript, in a way that has (to my knowledge) no parallel in Python.

As in rur-ple, I have a robot "class" called UsedRobot which is broken (i.e. like the original Karel it can only turn left, etc.).  For completely separate reasons, I had decided that I would actually implement a PrivateRobot "class" within the RUR  namespace, which would not be directly exposed to the user, and have UsedRobot "inherit" from it.

Here's what one can can do


var r = new UsedRobot();      // does not have a turn() method
RUR.PrivateRobot.prototype.turn = RUR.PrivateRobot.prototype.turn_left;   // give such a method to the "parent"
r.turn();  // turns left using the new parent's method.
UsedRobot.prototype.turn = RUR.PrivateRobot.prototype.__turn_right;  //give different method to "child"
r.turn();  //  turns right - look up stops at "child"
delete UsedRobot.prototype.turn;
r.turn(); // turns left again  - look up goes up to parent since method no longer exists in child.

I still prefer Python to Javascript ... but I find that one can do neat things in Javascript which (to my knowledge) can not be done in Python.   Caveat: the fact that something like the above can be done in Javascript does not mean that it should be done.

===
Adam, in the comments, pointed out that something similar can be done with Python, using instance.__class__ to modify the behaviour of a class.  For example:


class A:
    pass

class B(A):
    def turn(self):
        print("turn left")

def right(self):
    print("turn right")

b1 = B()
b2 = B()
a1 = A()
b1.turn()  # prints turn left
a1.__class__.turn = right
a1.turn() # prints turn right
b1.turn() # prints turn left
del b1.__class__.turn
b1.turn()  # prints turn right