Posts Tagged: ood


30
Aug 10

Monads in an Object Oriented context

The other day I was referred to a blog post jQuery is a Monad. That is an interesting post which if you have any interest in Monads should read. My first thought was that jQuery was another implementation of Fluent Interface and it just did not strike me as a monadic construct.

There are blog posts which take an essential thought or a message and by putting together various arguments bring it to some logical conclusion. This post is not one of them. It just describes the results of my thought process which started off contesting the assertion, to accepting it and then realising that either way, it really didn’t matter a whole lot. I don’t claim it to be sufficiently accurate except to state that it is accurate only to the best of my belief and understanding. Pointers to any inaccuracies or alternate interpretations in the comments shall be gratefully received. And yes, this post in the end reaches a somewhat boring conclusiion.

Having got that little expectation management out of the way, lets get back to monads, jQuery and Object Orientation. Writing a tutorial on Monads is a rite of passage for many. Thats something I’ve never done. And I don’t wish to, but I cannot escape the fact that I’m going to have to introduce monads to those who are as challenged in their understanding as I am.

What are Monads ?

I’ll give you the loose idea. Whenever a function completes any computation, the results of the computations are often returned as the return value of the function. But every once in a while you need a container around that return value. A container to store the state of a computation, sometimes with additional metadata or historical annotations for use later. At its very basis, a monad is a container for storing computations and being the container to be carried between functions. Think of it as a shipping container if you will, which moves materials between factories – the factories being various functions which operate on the contents of that container.

But it takes more for a monad to be a monad than just being a container. Given any content, the monad should be able to construct itself by wrapping itself around the content. Thats what the source factory invokes when it fills up the container with goods. Some prefer to call it a type constructor – the type here being the container, or the monad (which may internally contain goods of various types, but I get ahead of myself).

In addition once the container reaches the destination factory, unlike typical container, this one does not just allow its contents to be unloaded. Nay, that would make it too simple. In this case, the container has to be taken to a factory where it allows a robotic arm of the factory to plug into a receptacle it provides, which the factory can use to extract the underlying values, often one at a time. The factory further processes these goods, which again come out at the other end of the factory as a different set of containers. And it is quite likely that the type of the goods in the new containers could’ve changed.

That in essence is a monad. Easy, right ? I’m sure not and I’m now only going to make it a bit harder.

The wikipedia, definition of monad Monad

I’m just going to let you read the definition as provided by wikipedia.

A monad is a construction that, given an underlying type system, embeds a corresponding type system (called the monadic type system) into it (that is, each monadic type acts as the underlying type). This monadic type system preserves all significant aspects of the underlying type system, while adding features particular to the monad.
The usual formulation of a monad for programming is known as a Kleisli triple, and has the following components:

  1. A type construction that defines, for every underlying type, how to obtain a corresponding monadic type. In Haskell’s notation, the name of the monad represents the type constructor. If M is the name of the monad and t is a data type, then “M t” is the corresponding type in the monad.
  2. A unit function that maps a value in an underlying type to a value in the corresponding monadic type. The result is the “simplest” value in the corresponding type that completely preserves the original value (simplicity being understood appropriately to the monad). In Haskell, this function is called return due to the way it is used in the do-notation described later. The unit function has the polymorphic type t→M t.
  3. A binding operation of polymorphic type (M t)→(t→M u)→(M u), which Haskell represents by the infix operator >>=. Its first argument is a value in a monadic type, its second argument is a function that maps from the underlying type of the first argument to another monadic type, and its result is in that other monadic type. The binding operation can be understood as having four stages:
    1. The monad-related structure on the first argument is “pierced” to expose any number of values in the underlying type t.
    2. The given function is applied to all of those values to obtain values of type (M u).
    3. The monad-related structure on those values is also pierced, exposing values of type u.
    4. Finally, the monad-related structure is reassembled over all of the results, giving a single value of type (M u).

In object-oriented programming terms, the type construction would correspond to the declaration of the monadic type, the unit function takes the role of a constructor method, and the binding operation contains the logic necessary to execute its registered callbacks (the monadic functions).

In practical terms, a monad (seen as special result values carried throughout the pipeline) stores function results and side-effect representations. This allows side effects to be propagated through the return values of functions without breaking the pure functional model.

The bind operation

So coming back to the container analogy, the container is the monad, the goods are the underlying types, and the factory is a function which takes a underlying type and spews out another monad which contains the newly manufactured goods. There is a difference to be noted, the container doesn’t go into the factory, its the factory thats plugged into the monad through the bind operation, which triggers the processing. Also note that the output of each such factory is not just goods, but containers of such goods it manufactures.

There, you can now imagine a series of containers and factories, or monads and functions which are sequenced to assemble a pipeline to produce the desired goods / computations.

Before we go on to how this works in OO, I would like to spend some more time on the function thats provided to the binding operation. This function accepts the individual contents of the incoming container and returns a container with the newly manufactured goods. A somewhat similar function is used when using map operations on containers eg. Lists. So if I had a list of integers, and I wrote a function which doubled their values, then the map operation would be written in python as :

1
2
3
4
5
def twice(val): return str(2 * val)

print map(twice,(1,2,3,4,5))

#Expected output is :['2', '4', '6', '8', '10']

This is a good example where the container (tuple) is unbundled inside the map operation, each constituent value of the list is passed to the twice function, and all the results of the twice function are reassembled into yet another container (list). The type of the constituents also changed from ints to str (string) along the way. To be a strictly monadic construct, the twice function should’ve returned not just the double of the value, but a double contained in some other container (either a tuple or a list), and the map function should’ve extract the individual strings from each of the individual tuples/lists and constructed a final tuple / list out of the same.

While unlikely to be confused as so, let me restate for clarity, the map function is not the monad. The tuple and the lists are the monads here. The map function is an example of the contextual capabilities that monads expect from their environment (eg. via and around the bind operator in haskell). And twice is the operation thats performed on the monad. Again to restate, the monadic chain is like a set of factories that spew out containers, which allow other factories to plug into them and in turn extract the contents and then spew out even more containers.

Monads and Object Orientation

So how does this work in an object oriented context ?

Lets take rules 1 and 2 of a monad. If I was to declare a class which had a constructor which took in a value and then wrapped it, then I would satisfy these two rules for being then be able to suggest that the class is a monad. However the rule 3 gets a little bit more interesting. Object oriented languages have the “.” operator which is somewhat analogous to the do block which can chain operations. So if I was to write o.foo() that would be equivalent of suggesting that I invoke the method foo() on the object which being a member method of the class has access to all the object internals and thus is able to access the wrapped value and do the necessary computations. Now if foo() were to return any object again of a class which satisfies these very rules, then I would be able to say that this class along with its member function foo() is a reasonable object oriented analogy of the monad. And I would be able to start chaining the methods as in o.foo().bar().baz()

Whoa! let me restate that again. If a class, has a constructor which takes a value and wraps that value, and has a number of additional member functions which each operate on these underlying values and return an instance of either the same object or another object of a class which follows the same rules, then I can say that that particular class is a monad. Incidentally thats exactly what fluent interfaces do, except that they do not have any specific expectation of wrapping. And a large number of classes may incidentally fit this description. And if jQuery is a monad, so are all of them.

Well, we did relax a few constraints along the way. First of all the functions are not stand alone functions. They are member methods which have direct access to the underlying wrapped value. Secondly they themselves don’t return a monad around an individual item in a collection. They return a monad around the entire collection of values. Thus the complexities and capabilities of the do block and the bind function are substantially simplified when using the “.” operator. And finally going back to the container analogy, the class defines and consists of both the containers and the factories. Seems like the threshold for stating a particular class is a monad is actually quite low. Turns out we reached a boring end. And it seems we are not much wiser at least in terms of any specific conclusions or insights. But every once in a while sometime the journey is more exciting than its end. For me this did seem like one.

Why are objects simple and monads complex ?

At least for me the above was true. Turns out objects collate related data and functions together into one class. Also the do block and bind operator on an object is very simple. So for many especially coming from the OO school, objects are well understood. On the other hand understanding the requirements of monadic constructs takes quite some time. So there’s a lot of gray cells that need to be exercised to start understanding what a monad is and how the various requirements for a monadic construct can be satisfied. And when mapping between monads, and objects which can also be seen to be monads, a lot of that complexity is either partially waived (eg. functions returning monads, the infrastructure around bind operators unbundling and bundling monads) or just simplified (functions and underlying values being colocated in the same class, the “.” operator being a far more simplified version of do block). But after some substantial headaches, it does start to seem that perhaps, just perhaps, monads aren’t so complicated after all :) .

So is jQuery a monad ? I believe one could choose to be very pedantic and point out minor issues with that assertion. Or one could accept that the intent of monadic sequences are well represented in jQuery chains and accept it as one. I started with the former and ended at the latter position. Would I express that jQuery is a monad ? To the monadically challenged – No. That obfuscates far more than it enlightens. To them I would say jQuery is a fluent interface which allows continuous chaining of operations on an underlying set of dom objects. And is there a big “Aha moment” when one realises that jQuery is a monad ? I couldn’t find one. While the journey of trying to understand monads and correlate it with monads was very exciting, at least the OO practitioner in me is unlikely to have missed much had I not known that. But I got to understand monads better – and thats well worth the time, and all the headspinning.


26
Aug 10

A case for non leaky dual abstractions.

A long long time ago, I worked on a fairly complex piece of design. And like any well behaved designer, I broke it down into a number of abstractions that made it manageable. I gave the abstractions funny sounding names. And before long I found those abstractions finding their way into the user interface. Abstractions which made no sense to the end user.

That experience taught me a good lesson. In attempting to deal with complexity, I was attempting to come up with the appropriate abstractions in a very bottom up way. So, strategic closure (of the Open Closed Principle), dependency inversion principle, et. al. all found their way into these abstractions I was modeling. These abstractions represented themselves via the various programmatic interfaces in the software design and their roles. At the same time there was a different perspective of the software. The way the end users would’ve preferred to see that software. The abstractions the way the end users saw the system were sometimes different than the underlying abstractions I modeled.

In a good design, the two abstractions should line up, and if there is an inconsistency, there is probably an issue with the design. Certainly this could be an issue in some cases. However in many cases the underlying backend might be built to offer far more capabilities than what are being exposed through the early version of the user interfaces. Probably there are multiple intents for which the software is being designed, and the particular user interface on table is just one of them. Probably, the underlying complexity of the back end is way too high which requires a very different nature of bottom up abstractions, which are different from the top down ones. Frankly, the reason doesn’t matter. Even after so many years, I look back and am comfortable with the thought that there needed to be two abstractions – one top down and one bottom up, one front end and one backend.

Fast forward many years. Another example helped me further attain some insight into the matter. We had a bunch of mobile smartphones floating around with the traditional PC UI abstractions being carried over into their design. Along came an iPhone – which rethought the interface the way users would’ve preferred to see the interface. Now iPhone was built on a traditional operating system. So it had the same abstractions that these operating systems have in the backend. However it decided to change some of the front end abstractions – in tune with the target market and the device / form factor peculiarities. Did the iPhone change the backend abstractions baked into its software – most likely not. However it changed the frontend abstractions, just enough to make the experience really simple and easy for its users.

As an engineer, I have lived with the regret of allowing backend abstractions to leak into the front end. But I have learnt something along the way.

  • Don’t let the inapplicable frontend abstractions leak into the backend. This is especially true for most reasonably complex software. Strictly top down design can lead to a lot of brittleness in the long run, requiring very substantial surgery eventually.
  • Don’t let the inapplicable backend abstractions leak into the frontend. In most cases this is a usability nightmare. ’nuff said.
  • Realise that you have to simultaneously service independent expectations ie. robustness of usability and robustness of modeling. Work with both the abstractions to mould each of them well: Work your frontend abstractions well enough to mould them to reflect the use cases of the software in the most usable manner. Work with the backend abstractions to let them emerge from the problem space you are trying to resolve at the backend. Now make sure you work with both of them to map them into each in a reasonably smooth fashion. This is easier said than done. But doing it is whats necessary.

PS: I am not referring to what is conventionally referred to as leaky abstractions, where the implementation leaks into an abstraction. I am referring to a set of frontend and backend abstractions leaking into each other. However if all the backend abstractions were to be treated as an implementation, then this would be a case of leaky abstractions as well.


15
Feb 09

So were Jeff / Joel / Uncle Bob discussing happiness and fitness ?

For those who are still unaware of the Quality and Testing discussion, I would refer you to the first half of Do you wanna be the Picasso of programming? First learn the rules, and only after break them to first come upto speed on the events.

Subsequently Jeff Atwood wrote Real Ultimate Programming Power and I posted a comment on it which compared the issue to that related to fitness (search for fitness to reach my comment). Thats what also made me realise that if one really looked at the entire discussion as one between Happiness and Fitness, it just seemed so much easier to understand and comprehend.

So if one goes back to the first podcast #38 where Joel appears to take on software quality, and if one takes up an analogy where software usability and customer satisfaction are treated as happiness (of the software) and the quality is considered as fitness (again of the software) then what Jeff and Joel seem to be primarily saying is that (words are entirely mine)

In the overall scheme of things happiness is more important than fitness.


That would make a lot of sense that most would readily agree to. However one more statement in there says

Fitness doesn't matter so much



And thats what probably triggered off a whole bunch of reactions. It also seemed to offer an explanation of why there was such a storm raised.

The way I perceive it, Jeff and Joel were making an argument for happiness which probably would’ve gone unnoticed but for the fact that the portrayal of fitness was (if I may say so) a bit incendiary. It wasn’t so wrong as that it simply seemed to be sending out a completely wrong message. And if this was an opinion on some small blog it would still have gone unnoticed. But Jeff and Joel being the influential voices that they are were less than likely to be ignored especially when the message they were sending out was considered “dangerous” by the fitness community. Dangerous in the sense that it could lead to a whole bunch of people treat fitness with even lesser importance (especially in the context where general fitness levels were quite suspect). As I revisited the podcasts and the blog posts, the happiness / fitness analogy seemed to generally hold up.

This paragraph is a little speculative in the sense I don’t know that this is what actually happened and am speculating at my end. So Joe n Jeff got a little flustered about the fact that they couldn’t understand why they had kicked up a storm in the first place since they believed in what they had said about happiness. So they got together with Uncle Bob to sort things out in a subsequent podcast. To me it seemed like a rather uneasy and tepid podcast where they didn’t disagree with each other’s points of view but still continued to be uncomfortable with them. The multiple axes that were being referred to could’ve been happiness and fitness. Jeff still continued to defend their stance in a manner which perhaps only made matters worse. The Ferengi Programmer seemed to suggest that fitness regimens were bureaucratic steps (which cast them in a negative light) which were rather expensive to deal with and hence negotiable. The Real Ultimate Programming Power seemed to suggest that since most people wouldn’t worry about reading up on or attempting for better fitness, probably a much simpler set of rules along with a continuous thought to be more fit was what was really important.

I am convinced when I look at things in this perspective Jeff and Joel’s arguments make sense as do Uncle Bob’s. In my mind many of the differences can also be explained reasonably well by this analogy. It also explains why some of the statements seemed to invite so much ire. The issue probably lay in packaging of the arguments. If the statements are re-presented in a manner which does not seem to reduce the importance or desirability of fitness per se while continuing to emphasise the primary goal of happiness, it could be possible to close the discussion and move beyond the debate back into the real issues related to happiness and fitness, oops customer satisfaction and code quality.


12
Feb 09

An experienced programmer doesn’t use SOLID as a checklist – he internalises it.

Reading The Ferengi Programmer by Jeff Atwood really made me quite concerned. Here’s clearly an opinion which to me seems not grounded in sustained experience in applying the principles and is likely poor message going out to junior programmers.

In the post the author treats SOLID principles by Bob Martin as a ruleset that programmers apply from time to time. Once you get yourself into that frame of mind it is difficult to then contest the rest of the post. I would want to re-present the same topic with a different frame of mind.

SOLID principles are principles that you learn in your early days as a designer. These are formative stages when you are honing your skills and attempting to review your designs in terms of specific checklists of items to go through as a mechanism of validating your design. But each time you apply them, you internalise a part of them, and soon in 3 or more years of regular application, their application becomes internalised and ingrained. At this stage you might even well forget that they exist, since you apply them subconsciously, day after day, time after time, and sometimes referring back to them only when debating or reviewing your designs with other designers.

The analogy to the painter is in the post referred to : Are You Following the Instructions on the Paint Can? is also quite instructive. The instructions on the paint can are for one time painters, hobbyists, amateurs etc. No experienced painter is likely to be reading them since he’s probably internalised them. But each seasoned painter would want every junior painter to learn the instructions and the costs of not following them before stepping up to deciding whether and when not to follow them. He is unlikely to teach a new painter in the making – follow the instructions that make sense.

Sure you do make tradeoffs at times in design. Most people tradeoff guidelines in all spheres. However the keyword is to understand that you are breaking a guideline and then do so explicitly knowing its costs fully well.

My big difficulty with the post is that it is an advice which may do more harm to junior programmers than good. It might encourage them to make tradeoffs before they learn the cost and implications of making the tradeoffs. And it might set themselves away from a path that requires careful and judicious application (which requires a lot of effort in the early days) and helps them internalise the principles.

I would not recommend the post I refer to to any junior and upcoming programmer. My advice is as follows. If you have grown to a stage where you are applying these rules implcitly – don’t worry, you have the experience on your side to generally make the right judgement calls and you are likely to anyway apply them under most of the cases. In such a situation, this post and the one it refers to are probably inconsequential to you. If you are at a stage where you still need to review your design with respect to the SOLID principles (or other appropriate design principles) – please take your time to apply the principles, learn if you are breaking them, understand the costs of doing so (I would recommend that involve a senior programmer / designer in the process) and then by all means make the best judgement. Principles distilled over time and experience should be adjusted preferably by those who understand the cost and implications of doing so, the rest should strive to reach that state first.

To clarify, the reason why I upfront made the statement “seems not grounded in sustained experience in applying the principles”, is that those who have internalised them hardly every feel the burden (if at all) of applying them, and are unlikely to ever ever treat it as an explicit checklist, and they seem like checklists to those who haven’t internalised them. Precisely the audience to whom you want to craft a more careful and nuanced message.


25
Sep 08

Python from a Java perspective – Part 2 – How duck typing influences class design and design principles

Update: Modified the title to make it a little shorter.

This post talks about applying Open Closed Principle, Liskov’s Substitution Principle, Dependency Inversion Principle and Interface Segregation Principle in Python, coming from a Java programming background.

Background :
A few days ago I blogged about Commentary on Python from a Java programming perspective. In that post I avoided getting into the specific details with code snippets etc since I wanted to focus on how it feels.

One of the observations I made was that I thought coming from a Java background, that background helped me from a class design perspective. I ran into a couple of posts from the ObjectMentor blog, namely The Open-Closed Principle for Languages with Open Classes, and The Liskov Substitution Principle for “Duck-Typed” Languages. The gentleman behind ObjectMentor is Robert Martin, who wrote a number of articles in the mid 90s related to these design principles. (Links to PDF : Open Closed Principle, Liskov Substitution Principle, Dependency Inversion Principle and Interface Segregation Principle)

Sidebar : A Hat Tip to Robert Martin : Robert Martin used to contribute heavily to a number of newsgroups including comp.lang.c++ and comp.object in the early and mid 90s. I must confess a tremendous debt to him since my view of OO Design in those days was substantially influenced by his writings, and the design principles he talked about and later published as articles. These continue to guide my thinking about Object Oriented Design to this day. A hat tip to Robert Martin. He wouldn’t know me or recall me, but I used to participate in some threads occasionally, and read him regularly and that helped me tremendously learn so much about OOD and how to apply it in C++.

Having had applied these principles a countless number of times,in C++ and Java, I thought it would be an interesting exercise to document how class design changes even when the same underlying design principles are applied to a dynamic language (in this case – Python). The remainder of this post summarises the design principles and the examples that Robert Martin talked about in his articles, and how these get implemented perhaps a little differently when used in static typed (Java) and dynamically typed (Python) languages. His original source snippets in the C++ language can be found in the articles I have hyperlinked to earlier.

Open Closed Principle (OCP)

Software entities (classes, modules,functions etc.) should be open for extension but closed for modification

What this basically means is that the code you write should be in a manner where it does not need to be modified when you need to extend it – the design of the code should allow for the extension to be made by new code being added, not old code being modified.

In the example below Circle and Square are two Shapes which can be rendered. The design essentially sets out with an objective that it should be easy to add newer shapes (say triangles) without modifying existing code. Lets straight away get into the Java version of the code.

public class Painter {

    public static void main(String[] args) {
        // We sould like the shapes to be drawn in the
        // order of the shape types as found in this list
        List classOrder = new LinkedList();
        classOrder.add(Square.class);
        classOrder.add(Circle.class);

        // The shapes
        List shapes = new LinkedList();
        shapes.add(new Circle(1,1,5));
        shapes.add(new Circle(3,3,7));
        shapes.add(new Square(2,4,3));
        shapes.add(new Square(4,2,4));

        Collections.sort(shapes, new ShapeComparator(classOrder));

        for (Shape shape : shapes)
        {
            shape.draw();
        }
    }
}

// This declaration defines the contract across shapes
public interface Shape {
    public void draw();
}

public class ShapeComparator implements Comparator {
    private List orderedClasses;
    public ShapeComparator(List orderedClasses) {
        this.orderedClasses = orderedClasses;
    }

    @Override
    public int compare(Shape s1, Shape s2) {
        return this.orderedClasses.indexOf(s1.getClass()) -
            this.orderedClasses.indexOf(s2.getClass()) ;
    }
}

public class Circle implements Shape {
    private int x;
    private int y;
    private int radius;

    public Circle(int x, int y, int radius) {
        super();
        this.x = x;
        this.y = y;
        this.radius = radius;
    }

    @Override
    public void draw() {
        System.out.println("Drawing Circle at (" +
                x + "," + y + ") with radius " + radius);
    }
}

public class Square implements Shape {
    private int x;
    private int y;
    private int width;

    public Square(int x, int y, int width) {
        super();
        this.x = x;
        this.y = y;
        this.width = width;
    }

    @Override
    public void draw() {
        System.out.println(
            "Drawing Square at (" + x + "," + y +
            ") with width " + width);
    }
}

The Painter class here defines the order in which the various shapes need to be rendered (classOrder), creates a list of all the shapes (shapes), sorts the shapes list using classOrder and then renders all the shapes.

The ShapeComparator is a class which implements the comparator interface for Shapes (public class ShapeComparator implements Comparator) and implements the compare method which compares two shape instances and decides the relative order between them.

The remainder of the code should be rather self explanatory.

So where is OCP being applied here ? For that you have to imagine a new shape, say a triangle now being introduced into the mix. In this case, Triangle would be a new class which would implement Shape. No existing line of code will change. However the Painter main method will now add the new class in the classOrder list in the appropriate place, and if you want to modify the order in which the types should be rendered, just modify their corresponding class placement in the classOrder list. The essential thing to be noted is that Shape, Circle, Square and ShapeComparator are all “open for extension but closed for modification.”

So what does the corresponding python code look like ?

# Look ma ! No Shape class
class Circle(object):
    def __init__(self,x,y,radius):
        self.x = x
        self.y = y
        self.radius = radius
    def draw(self):
        print "Drawing Circle at (%s,%s) with radius %s" % \
                (self.x, self.y,self.radius)

class Square(object):
    def __init__(self,x,y,width):
        self.x = x
        self.y = y
        self.width = width
    def draw(self):
        print "Drawing Square at (%s,%s) with width %s" % \
            (self.x, self.y,self.width)

if __name__ == "__main__":
    order = [ Circle , Square] # the order in which to draw the shapes
    shapes = [Circle(1,1,5), Circle(3,3,7), \
                    Square(2,4,3), Square(4,2,4)]
    for shape in sorted(shapes,
            # Comparison function is embedded inline using a lambda
            lambda s1,s2 : order.index(type(s1)) \
                     - order.index(type(s2))):
        shape.draw()

What learnings can we get from this ?

The first most apparent difference is – No Shape Class. Where did it go ? Well, static typed languages use polymorphism as a powerful mechanism of extensibility. In other words, in many cases the extensions are likely to be newer derived types. Thus design the rest of your code to work on the base type and introduce the newer derived types later as required without having to necessarily change existing code. However static languages primarily depend upon inheritance as the vehicle for delivering polymorphism. Dynamic languages on the other hand depend upon duck typing. Duck typing supports polymorphism without using inheritance. In this context you need the same set of relevant methods to be implemented in each of the extension classes. The role of the abstract base class or interface as the one which specifies the contract / api has been made redundant. You can still choose to define a base class / interface if you want to, but you no longer have to.

Another thing to be noted is the way the comparator is implemented. While java required us to create a new one method class implementing a required interface, and then required us to instantiate the same and then trigger its functionality, python allowed us to implement it inline as a lambda. In a very different way this is OCP being applied (okay okay .. for those insisting on theoretical correctness thats not true .. but close enough) inside the language design itself. A function is an object in python, and a lambda is a special kind (not a subtype) of a function, and there are capabilities built into python to easily manipulate function objects / lambdas. The sorter method functionality was extended to allow custom comparators by specifying a particular evaluation expression as lambda. In java we actually had to implement the inheritance hierarchy ourselves before being able to leverage the extensibility in the list class for custom comparisons.

In the context of OCP, the learning is that dynamic type languages allow you to build extensibility by leveraging duck typing instead of type inheritance.

Dependency Inversion Principle (DIP)

  • High level modules should not depend upon low level modules. Both should depend upon abstractions.
  • Abstraction should not depend upon details, details should depend upon abstractions

To understand the principle, the reference point should be structured and modular programming scenarios prior to OO. If I wanted to book a tour, the tour booking function would in turn call functions to book a flight, book a car and book a hotel. All four function implementations would be in the parlance of the definition – “details”. And anytime you had to change the way any of them worked it would require a relatively high amount of effort to do the changes. If you applied DIP in such a scenario, you would perhaps have a function say TripBooker which would in turn call methods on other classes which implement the methods in an interface / abstract class to book a flight, car and a hotel. The actual detailed booking logic would now be implemented in another class. Thus TripBooker now depends upon an abstraction which specifies the contract, and it becomes much easier to change or plugin the concrete implementations.

As an aside I must note that I have found code which properly applies DIP creates enormous frustration amongst people coming from a procedural background and lesser oriented to this OO style when attempting to statically browse the source. (Java Eclipse users will understand the quote : “I was attempting to understand the logic. I did F3, F3, F3 and then I reached a interface.”, thats because attempting to decipher the logic invariably leads to an abstraction and the programmer has to now separately figure out which was the detailed implementation which would now get triggered). But thats a learning curve issue – not really an issue with DIP.

In the following example which is largely similar to (but not identical to) the example in Robert Martin’s article, we are having a Lamp with a button. All the class names from the example are retained. These are the two specific details – Lamp and ButtonImpl. The lamp has capabilities to turn on and off, but one would like to to move the exact mechanism of turning on and off (which might be hardware specific) into the detail but treat the ability to turn on and off as an abstraction (ButtonClient). Meanwhile buttons can have a variety of possible implementations one of which is ButtonImpl, which all share the essential characteristic that a button has one state with two possible values, can toggle between the states and have a reference to a ButtonClient to which they can communicate with.

Thus the model instead of having two details Lamp and ButtonImpl, with the details communicating with each other directly, one has the following design :

  • Detail Lamp implements (depends upon) abstraction ButtonClient
  • Detail ButtonImpl implements (depends upon) abstraction Button
  • Abstraction Button has a reference to (depends upon) abstraction ButtonClient

Here’s the code in Java.

public class ButtonHappy {
    public static void main(String[] args) {
        Button button = new ButtonImpl(new Lamp());
        button.toggle();
        button.toggle();
        button.toggle();
    }
}

public interface ButtonClient {
    public void on();
    public void off();
}

public class Lamp implements ButtonClient {
    @Override
    public void off() {
        System.out.println("Lamp turned off");
    }   

    @Override
    public void on() {
        System.out.println("Lamp turned on");
    }
}

public abstract class Button {
    private ButtonClient client;
    public Button(ButtonClient client){
        this.client = client;
    }
    public void toggle(){
        boolean newstatus = ! getStatus();
        if (newstatus) client.on();
        else client.off();
        setStatus(newstatus);
    }
    public abstract boolean getStatus();
    public abstract void setStatus(boolean status);
}

public class ButtonImpl extends Button {
    private boolean status;

    public ButtonImpl(ButtonClient client) {
        super(client);
    }   

    @Override
    public boolean getStatus() {
        return status;
    }   

    @Override
    public void setStatus(boolean status) {
        this.status = status;
    }
}

There’s probably no additional explanation required, so here’s the equivalent implementation in python.

class Lamp(object):
    def on(self):
        print 'Lamp turned on'
    def off(self):
        print 'Lamp turned off'

class Button(object):
    def __init__(self,client):
        self.client = client
    def toggle(self):
        status = self.get_status()
        if self.status : self.client.on()
        else: self.client.off()
        self.set_status(not status)

class ButtonImpl(Button):
    def __init__(self,client):
        self.status = False
        super(ButtonImpl,self).__init__(client)
    def get_status(self):
        return self.status
    def set_status(self,status):
        self.status = status

if __name__ == "__main__":
    btn = ButtonImpl(Lamp())
    btn.toggle()

    btn.toggle()
    btn.toggle()

We can again see here that one class that is missing but is no longer being missed ( ;) ) is ButtonClient and the reason is the same as in OCP – Duck Typing. In terms of the definition of DIP itself – abstractions no longer necessarily have to be implemented. They exist implicitly in the detail classes but are no longer explicitly documented.

Liskov Substitution Principle (LSP)

What is wanted here is something like the following substitution property:

If for each object o1of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.

Actually LSP is more of a test of whether two classes qualify to share an inheritance or is-a relationship, rather than a prescription for the design itself. In simple terms it sets out a requirement that if you define a new derived class, it should be possible to substitute an instance of a base class in a program (and though it doesn’t state it, an instance of a peer derived class ie a class in the same inheritance hierarchy) with an instance of a derived class without introducing any negative or unexpected side effects whatsoever. A rather simple example would be if we were to attempt to define a derived class of java.lang.String (say ConstrainedString) which now had an additional constraint (max characters – say 20 for a particular instance). To support this constraint a new runtime exception MaxLengthExceededException would need to be defined. It would have to be a runtime exception as you do not have the ability to add to the checked exceptions thrown by the java.lang.String class in ConstrainedString. Now programs that concatenated strings have no notion of having to react to a String overflow situation and this would create undesirable side effects in the program. Thus using LSP one could conclude that it would be incorrect to implement ConstrainedString as a derived class of java.lang.String.

I could not think of a good way of showing LSP in action in code since it is a test of candidate relationship and does not have any structural manifestation itself. However it is still a valid test to be applied in Dynamic Languages as well with one change as recommended in the post The Liskov Substitution Principle for “Duck-Typed” Languages .

What is wanted here is something like the following substitution property:

If for each object o1of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of substitutable for T.

Duck typing introduces looser coupling than inheritance but a coupling that has no static checks whatsoever. So the application of LSP in a designer’s mind is a little more interesting. Because the modified LSP is now a rather obvious statement which in loose term says “If A can be substituted by B without any side effects then A is substitutable by B”, on the face of things, it is no longer such a useful principle. But if you explore under the covers, the real interesting part has now shifted from “B is a subtype of A” to “If A can be substituted by B”. In static type languages, the places where A was being used was clearly known and easily searchable or navigable into from IDEs. Because this is now so much more difficult even though you are no longer explicitly attempting to apply LSP, you are on your toes the time far more often to avoid the situations that LSP was setup to warn you about.

A Sidebar : Refactorability : I received some interesting comments on my earlier post Commentary on Python from a Java programming perspective on this thread. My submission is that it requires you to come from a static typing background into a dynamic typing background to realise how much more difficult refactoring is. And the above mentioned implication of LSP in dynamic typing languages just goes out to demonstrate that there are indeed situations where the burden on you as a programmer / designer just went up due to the lack of explicit type information. This is but one of many aspect of many pros and cons between the two (static and dynamic typing) paradigms. To acknowledge it allows you to deal with it and work with it.

Interface Segregation Principle (ISP) :

Clients should not be forced to depend upon interfaces that they do not use

This is a little anticlimactic. The good news here is that thanks to duck typing, the client is actually now making the choice of what interface they choose to use. This is one principle that no longer needs to be explicitly applied. No more discussion required here.

Summary :
As we have seen duck typing does imply some changes to your class design. While the first three design principles continue to be relevant, their relevance is now a little different in your design process. It is important to be aware of these changes to adjust your design models in a more appropriate and idiomatic way. One would typically create lesser complex class hierarchies, especially with all the interfaces / pure abstract classes now no longer mandatory. Not only type information but even some of your abstractions are now less explicit.