Tuesday, March 07, 2006

 

Closures, essentials to dynamic OO languages

Closures, essentials to dynamic OO languages


Strolling once through the internet, I came across a Guido Von Rossum blog
stating about the fate of lambda and some Functional Programming related built-ins in python. Lambda was being chased out from release 3.0 for being redundant, misunderstood and ranked as intromision in our pure Python from those rascal followers of FP languages.

Well, just now we are watching the blooming of dynamic languages, started by many events, like the hype over Rails, the book Beyond Java, the blog departure of the hyperentusiasts and the like. I, for one, did my part starting a course (in portuguese, folks) about advanced object-oriented programming running both on post-grad and undergraduate Informatic programs here at University of Rio de Janeiro. This course teaches the basic of some dynamic oo languages, take a look at Web 2.0 phenomena, study interfacing issues like web, GUI and AJAX frameworks and read over concepts that make a modern language powerfull and productive. Listed among these concepts are comprehension, continuations, metaclassing, mixins and closures. Although sold as modern concepts, they are as old as the very first fully recognisable oo language: Smalltalk. Those visionaires at Xerox PARC conceived a powerfull and beautiful language that we mortals of oo programming will have to wait years for the world to get fit for it.

Right in the middle of Smalltalk, named with the modest name of block, there it was, the almighty closure. That is, the anonimous and portable block of code that can be
delegated and evaluated on demand within its original context. And that is the power of it, no burden or scaffolding imparted on the programmer, just the benefit of dynamicity and code shrinking ability. And lines of code cost money, more lines, more money to produce and maintain. As the number of lines increase the chances of understanding a code can dramatically reduce. And a well designed closure can save manyfold its size and be readily understood, just by the reading of itself.

Going back to Smalltalk or its contemporary counterpart Squeak, we can take a lesson or two. Take for example the all praised web framework Seaside. Its openly known to be the continuation based web framework. However it should be known as the closure based framework. Continuations are fashionable, while closure is just an intrisic feature of Squeak, so intrinsic not to deserve further attention. The delayed execution of a delegated block, is just what you need to deal with asynchronism of web interaction. Most signatures in Seaside take closures as a parameter. For sake, a web form is renderized from a single and very big closure containing all fields, links and actions.

Closures (or its poor counterpart lambda in Python) are not freaks coming out of FP nightmares, but instead a powerfull tool in both respectable OO and FP paradigms. Closures in OO take the powerful shape of pluggable behaviour, the very innards of a great number of design patterns. But seeing is believing, lets see some closure magic working a tenfold code line disappearing act. The visitor is a complex behaviour pattenr, central to any serious OO design. A pattern with many drawbacks, originator of gigantic inheritance trees, very fragile to any change on the object operational interface. Enters closure..


The Full Metal Planet is a game where a plethora of mobile units attempt to move over a ill tempered surface of many textured terrains. A boat can sail in sea but run dry at reefs, while a tank can roll on land but get stuck at marshes. To match the movements of rolling, climbing and sailing units with propicious kind of terrain, we should be using a double-dispatch. The double dispatch is a simplified visitor that runs on single object instead of a composite. Notwithstanding, suffers the very same drawback of its visitor counterpart.

Instead of using a conventional tree deriving units and terrains for each kind, lets use a generic closure driven unit/terrain architecture. Here Units are trained by initialization closures on how to behave when requested to climb, roll or sail over a terrain. On its side, Terrains have closures to know what to ask from prospecting units. When a unit probes to be accepted by a terrain, it is prompted to move by the proper moving action that was plugged in the terrain to characterize its kind. Now, each moving action is a method plugged into the unit, stating its ability to go ahead rolling, climbing or sailing. That is all and simple. Try your hand in building the whole tree with all combination of unit abilities and terrains, to end up with up to ten or more new classes. Not to remember the nasty weather on FMP, where land can be flooded and water can be dryed, and figure out more engineering, where a single closure assignment would suffice. Just pay attention that no ifs where required, so classes are open to new terrain kinds and unit abilities.



  1. class Terrain:pass
  2. def no(): print "failed to move"
  3. class Unit:
  4.   """This default unit is a tank, rolls over land, but can not sail"""
  5.   def __init__(self, roll=lambda go:go(), sail=lambda s:no()):
  6.     self.sail=sail
  7.     self.roll=roll
  8.     self.origin = Terrain()
  9.    
  10.   def move(self,target):
  11.     self.terrain = target
  12.     target.accept(self,lambda s=self:s.leave())
  13.   def leave(self):
  14.     self.origin.accept(self,lambda s=self:s.go())
  15.   def go(self):
  16.     print "moved"
  17.     self.origin.leave()
  18.     self.origin=self.terrain
  19.     self.origin.enter(self)
  20.  
  21. class Terrain:
  22.   def __init__(self, unit=Unit(), kind=lambda unit,action:unit.roll(action)):
  23.     self.accept = kind
  24.     self.unit = unit
  25.   def leave(self):
  26.     self.unit=None
  27.   def enter(self,unit):
  28.     self.unit=unit
  29. class Fmp:
  30.   def main(self):
  31.     tank = Unit()
  32.     land = Terrain()
  33.     boat = Unit(sail=lambda go:go(),roll=lambda x:no())
  34.     sea = Terrain(boat,lambda unit,action:unit.sail(action))
  35.     ocean = Terrain(None,lambda unit,action:unit.sail(action))
  36.     boat.origin=sea
  37.     tank.move(land) # succeed!
  38.     boat.move(land) # fails
  39.     boat.move(ocean)# succeed!
  40. if __name__ ==   "__main__":
  41.   fmp  =  Fmp()
  42.   fmp.main()
  43.    
  44.  

Wednesday, December 21, 2005

 

Well, should start blogging

Once upon a time I met with literate programming. I was told about it that you should try to express yourself in words before starting programming. It came back into my mind when I came across with - why you should blog . Indeed Stevey is right, writting things just straight up your thoughts. Well, thats my first attempt. And there should not be expectations on long blogs for a while. Because I am an inept typist, and its a pain to roll it out in such an sluggish pace. Take it as an awful excuse but that is it, I will keep it short and short it was indeed!

This page is powered by Blogger. Isn't yours?