Saturday, April 29, 2006

Twisting and Shaping DSLs using Ruby Metaprogramming

I write this in response to Federico Feroldi's comment to my previous post on defining simple DSLs.

[..] while reading your article I was thinking about using the recipe name string as an object to route the messages coming from the ingredients and then catching them by implementing missing_method in the string object...
So, for:

recipe "italian breakfast" do
   caffe = 1, :macchiato
end

is there a way to translate it into:

"italian breakfast".caffe(1, :macchiato) ?
[..]

Let's see:

"italian breakfast".caffe 1, :macchiato

First of all, I removed the brackets because I don't believe in brackets :-)

What Federico proposes can be done, but I am not sure I would do it this way, unless I am working  only within the context of a DSL.  If you want your recipe-string to accept the caffe method, then you have to override the method_missing method of the String class, which can be a dangerous thing to do if you have loaded other meta-code that overrides this method on a String or Object level.

I would rather go for a Concept Wrap Up:

Recipe("italian breakfast").caffe  1, :macchiato

where I make explicit the meaning of 'italian breakfast' by wrapping it into a Recipe object.  Note that I did not use Recipe. new.  I am launching a campaign against the use of new in application code, which I consider at the same level of badly used hungarian notation (because there is such a thing as good hungarian notation).

Another way I would do it is by using what I call a Conjunction:

"italian breakfast".consists_of.caffe  1, :macchiato

You will have to inject a consists_of method in the String class, which will act as a conjunction between the String and the method call.  The conjunction will take the String and wrap it up in a Recipe object.  The cafe method is then invoked on the Recipe object.
   
In both cases we have moved the handling of the method_missing from String to a custom made Recipe class.

The conjunction will be:

class String

  #Recipe conjuction

  def consists_of

    Recipe .new self

  end

end


The Recipe will start as:

class Recipe

  def initialize recipe_name

    @name = recipe_name

    @ingredients = {}

    register_with_global_repository

  end

  def method_missing method, *args

    @ingredients[method .to_s] = args

  end

    ...

The method_missing is catching the ingredients and it stacks them nicely on an hashtable.  Why do we need the register_with_global_repository call, though?

Since we are working with a DSL and we are not explicitly storing a reference to a created recipes in a variable, then we get the Recipe to self-register itself with a global centralized repository.  I could have made it a @@all_recipes class attribute, but I think that in this simple example it looks clearer as an external separate entity:

$RECIPES_REPOSITORY = {}

class Recipe

 

  private

  def register_with_global_repository

    $RECIPES_REPOSITORY[ @name] = self

  end

end

and finally the code to print out the recipe:

class Recipe

 

  def report

    puts "to make #{@name} you should buy:" 

    @ingredients.each_pair do

      |ingredient,description|

      puts " * #{Array(description).join ' '} #{ingredient}"

    end

  end

   

end


What is still missing is a method to print out the recipe directly from the DSL.  We would like our call to look like this:

recipe? "italian breakfast"


This snippet fully satisfies our language choice:

def recipe? recipe_name

  $RECIPES_REPOSITORY[recipe_name].report

end

Our new DSL now allows us to write:

"italian breakfast".consists_of.caffe  1, :macchiato

recipe? "italian breakfast"    

and to obtain:

to make italian breakfast you should buy:
 * 1 macchiato caffe

The one big limitation is that at the moment you can define recipes with only one ingredient.

We get around this limitation by making the method_missing a Follow Up Method Chain:

def allow_method_chaining() self end

def method_missing method, *args

    @ingredients [method.to_s] = args

    allow_method_chaining

  end

The trick here is that after having defined an ingredients we still have the original Recipe object ready to accept new ingredients.

You can now do:

"italian breakfast".consists_of.

                    caffe(1 , :macchiato ).

                    cornetto(1, :cioccolato)

 

recipe? "italian breakfast"   


and get:

to make italian breakfast you should buy:
 * 1 cioccolato cornetto
 * 1 macchiato caffe


That was long! I think I will now go for a 1 cioccolato cornetto!


Friday, April 28, 2006

The Way of Meta - Part IV - Hijacking Local Variables in DSLs

The Way of Meta

~

V. 0.0.4


Not long ago I have read the 'Creating DSLs with Ruby' article written by Jim Freeze, where he explains how to forge a DSL step by step, creating a new human readable formalism on top of ruby.  I really enjoyed the article as it went along some of the lines of thought that I have been working on for a while.

In the article there was a point that was left somewhat open: how to allow developers using a DSL to assign values to new concepts that they define on the spot, and then get access to both these concepts and their values from within the DSL.

I realize I have been a bit vague here, so I'll give you a straightforward example.  Let's say we want to define a DSL to describe the shopping list with all the ingredients needed to make a certain recipe..

Ideally we would like to write something like:

shopping_list_for "BLT sandwiches for the picnic" do
  sliced_bread = 3
  lettuce = 2
  tomatoes = 6, :red
  bacon = 4
end

The do..end block delimits a block context that gets passed directly to the shopping_list_for method.
This method should then extract the various ingredients and their quantity and description.

How can it do that?  One way is to run the block within a context where those ingredients already exist as methods.  This context would be a class with -for example- the sliced_bread= method overridden to accept the DSL input.

What about new ingredients that have not been specified a priori ?  Your metaprogramming instincts will tell you to go for a method_missing based technique.  Wrong.  Unless you specify a self (or other object) in front of sliced_bread, ruby will simply assume that it is a local variable rather than a missing method.  Highly annoying if you ask me, but it is necessary to avoid even worst problems and ambiguities when dealing with stuff like mixins.

You are left with these three choices:


shopping_list_for "BLT sandwiches for the picnic" do
  self.sliced_bread = 3
  self.lettuce = 2
  self.tomatoes = 6, :red
  self.bacon = 4
end

Argh!


shopping_list_for "BLT sandwiches for the picnic" do |recipe|
  recipe.sliced_bread = 3
  recipe. lettuce = 2
  recipe. tomatoes = 6, :red
  recipe. bacon = 4
end

Just a tad annoying


shopping_list_for "BLT sandwiches for the picnic" do
  @sliced_bread = 3
  @lettuce = 2
  @tomatoes = 6, :red
  @bacon = 4
end

The best so far.. you can visualize the @ as bullet points ant it is kind of ok..
Kind of.

Jim, at this point, proposes to drop the equal sign to force ruby to recognize the new keyword as a method that gets routed through method_missing.

shopping_list_for "BLT sandwiches for the picnic" do
  sliced_bread 3
  lettuce 2
  tomatoes 6, :red
  bacon 4
end

I'll admit it, this is not bad at all.  Yet it annoys me to no end that I cannot just get those variables that I need from another context.

Thinking about there is a way to get variables, and that is the local_variables method, but you have to execute it within a specific context.  There is also a method to pass around contexts, and that is binding.  What we have to do is to get the binding of the block and to get the local variables within the context underlying the binding.

I tried to call the block and then get the binding of the block, but it didn't work.  The block gets executed and the variables fall out of scope and become unavailable. 

I had to get the block itself to return the binding.  This can be done and it works, but the binding looks totally out of place..

shopping_list_for "BLT sandwiches for the picnic" do
  sliced_bread = 3
  lettuce = 2
  tomatoes = 6, :red
  bacon = 4 
 
  binding
end

Here it hit me that I could alias the word binding to something that would look good with end.  What about the end ?  I know it's tacky, but in its own tacky way it works and sounds credible:

shopping_list_for "BLT sandwiches for the picnic" do
  sliced_bread = 3
  lettuce = 2
  tomatoes = 6, :red
  bacon = 4 
the end

This is the code that allows the DSL to work and to print out the shopping list:

def report recipe, ingredients

    puts "to make #{recipe} you should buy:"

    ingredients.each_pair do

        |ingredient,description|

        puts " * #{Array(description).join ' '} #{ingredient}"

    end

    puts

end
 

def shopping_list recipe

    shopping_binding = yield

    ingredients = {}

    eval("local_variables" , shopping_binding).

    each do |var|

        ingredients[var] = eval "#{var}" , shopping_binding

    end

    report recipe, ingredients   

end

 

alias the binding
 

shopping_list "english breakfast" do

    tomatoes = 2, :green

    sausages = 3

    eggs = 2, :big

    bacon = 4

the end

 

shopping_list "banana milkshake" do

    milk = 1

    bananas = 2   

the end


When you run it you get:

to make english breakfast you should buy:
 * 2 green tomatoes
 * 3 sausages
 * 4 bacon
 * 2 big eggs

to make banana milkshake you should buy:
 * 2 bananas
 * 1 milk




Wednesday, April 26, 2006

Pandora Music Genome

Wow! That's all I can say, make sure you check this out: Pandora

It models what you like in music and makes very very sensible suggestions.

For example I like mellow rock with female vocal-centric aesthetics in minor key tonalities! Now I know what to answer when I am asked what music I like!

This Pandora thing is scary scary..

Ruby for Javists Presentation

I am scheduled to give a 40mins presentation on Ruby to a group of javists (both standard edition and enterprise guys :-)

Do you have any advice on how to present it and what to show them?

I am not going to do the Ruby is Better than Java number, since that would feel offensive, but I would like to make them want to have a taste of ruby... I would like them to leave with a desire to explore new things.

Any advice is well appreciated!





Friday, April 14, 2006

Software Superheroes

If there is one great thing about developing software is that software is probably one of the very few professions out there where you can be an awe inspiring Superhero.

Imagine if you were digging holes, moving rocks or filling in papers. How much difference would your skill make? You could perform maybe twice, three times better than an average worker. That's wholesome and fine, but how does it compare to superheroic feats such as flipping cars, vaporising enemies and flying at mach3?

Well, in software you can be that kind of superhero. Every improvement that you make, every skill that you learn, allows you to write better software and to handle greater complexity. If you can handle complexity you can build intellectual augmentations that are like a small army of cybernetic agents working for you. You harness the power of your skill and your agents, you simplify and organize and you move towards even greater levels of complexity.. that you can handle using abstractions. Your relative effectiveness is moving along an exponential curve by leveraging the previous software layers.

If you are a hotshot ruby programmer with a mastery of metaprogramming and you do dynamic programming con gusto, then you can take on a small IT department. Compared to a dozen of mediocre ASP programmers that copy and paste queries inside html code you are like a small determined hitech army. They won't even have the time to react. You are too fast for them. You do things they don't even comprehend. Sometimes they don't even understand that you are doing anything at all!

It's fun to be a superhero in the software world

(image by Chip Kidd)

Thursday, April 13, 2006

Lisp, the 'Why' way

I can't believe I found this. This is a comic book guide to lisp in a whyesque style. Great way to get started.

Wednesday, April 12, 2006

CodeSushi: Covering the Italian Scene

Staring from today my CodeSushi blog is going to cover specifically the italian scene and it is switching to italian.

Using CodeSushi as a platform and meeting point I am going to push directly the italian software development scene  and see what comes up  from there. 

The Liquid Development blog will continue as usual.

And remember.. Code Sushi, not Spaghetti Code ;-)


Tuesday, April 11, 2006

Software Management as Development of a Business Abstraction

A very pretty piece from Joel - or how you know when management is failing badly.

It is too often the case that developers -and employees in general- have to pay with extra working hours for management failures..



Monday, April 10, 2006

Concrete Patterns Example

I dug out an old link to some concrete examples of Patterns.
Considering how hard it can be to explain some of the esoteric development stuff, this can be an inspiration for us all.


Saturday, April 08, 2006

The Book is Out (?!)


What can I say?

I think that Kumo has got far too much time on his hands!

Thanks Kumo, much appreciated :-)

Let's say it's a late April Fool..

Friday, April 07, 2006

Upcoming Development Events in Italy

Italy has never been very active on the international development scene.  Let's see if we can turn this around :-)
 
Just a few links that make me proud:

Style and Stanzas

The same piece of code can be written in a thousand ways, and every way has different tradeoffs in terms or readibility, expressiveness, debuggability, verbosity, etc..

Jean-Charles Carelli recently asked on the rubytalk mailing list how to improve on the following style from the pickaxe book:

# 1 Book example
songs.append(Song.new(title, name, mins.to_i * 60 + secs.to_i))

# 2 Alternate version.
duration = mins.to_i * 60 + secs.to_i
songs.append(Song.new(title, name, duration))

I like a multi-line nested format, that I call Stanza - you know, like in poetry.

It looks like the following:

songs.append Song.new(
                   title,
                   name,
                   duration = ( mins.to_i * 60 + secs.to_i )
             )

It clearly shows you what you are appending as a chunk of code on the right. the 'duration =' idiom makes the intent explicit.  I use brackets to nest conceptual entities (Song, duration), so that they stand out as visually striking, which is useful if you are doing some Gestalt Code Reading.

Sometimes, using metaprogramming I also get rid of the explicit new by wrapping up object instantiation with a Song(..) method on the top level.  I use this Implicit Constructor because I don't want to be concerned with object creation in my code, just with the meaning of the entities that I am manipulating.

songs.append Song(
               title,
               name,
               duration = ( mins.to_i * 60 + secs.to_i )
             )



Wednesday, April 05, 2006

Perceptual Stances: Start Small

I am interested in the tricks and hacks that we can use to somehow 'mechanically' steer and control our perception.  

Presentation Formats are one way to do this, forcing you to express some content within an artificially imposed presentation frame.  The unusual 'shape' of the container can force you to reshape the content and discover some previously hidden properties.

Perceptual Stances (Thinking Formats?) do the same thing by forcing us to focus only on certain aspects of our subject matter.  Business Pundit wrote an interesting post that points out how you can unleash your creativity and get started by focusing on small thing rather than on grand theories and stereotypical thinking.

It strikes me that some of the examples he uses seem almost related to techniques I found in Drawing On The Right Side of Your Brain: Drawing Negative Spaces and Semantic-Neutral Drawing.  These are not the names the author would have used, but if you are interested I can expand on them.



Presentation Formats: Lightning Talks

Lighnting talks are quick nuggets of information, usually delivered within 5 minutes. I like formats, because they force you to take unusual approaches and points of view. I like space and time constraints, because they force you to be synthetic and expressive.

Have a look at the Lightning Talk format:
* Giving Lightning Talks
* Lightning Talks

Tuesday, April 04, 2006

Gestalt Code Reading

This is a follow up from some considerations in the comment section of the previous post.

If you have been writing code for some time I am sure that from time to time you also experience the weird psycognostic power of gestalt-reading code.  When I say gestalt-reading I mean that feeling of absorbing the main points and relationships of code by simply giving it a quick glance, just flicking through several pages of code. 

You don't know exactly what you have read, but you somehow have an overall impression of what the code does and how the different abstractions are related.

What do you think this is due to? 

I believe it is a mix of code indentation, code conventions, general domain culture and the ability of visualizing code on the fly via iconic images.  Next time you use your superpowers pay attention to what is happening within your perception process.  If your perceptual habits are even a little bit similar to mine, you will probably notice that when you read code you see little boxes and arrows, popping into existence on the backstage of your counscius awareness, connecting together according to well-known patterns.

The knowledge of this process may turn out to be quite important when deciding what code should look like.  Proper alignment of braces and indentations.. the feeling of un-closure that I sometimes feel when looking at python code (it feels more like a flow than like legos).  My mind looks for visual patterns and simplifies them into icons and boxes, probably also relying on subtler cues and unconscious processes to build meaning.

It's interesting to see what information we can get from this kind of code reading.  I can get the main conceptual entities because I can visually spot classes and attributes.  I can get the broader relationships too, probably because of a good rational choice of class names, sometimes due to the naming of attributes, occasionally by seeing how some object instances are built and attached to each other.  I rarely get the algorithms at a first glance, although I seem to remember that I used to be able to, before doing OOP.. but I am not sure if that really was the case, in the same way as I can do it now with objects.  One thing is for sure: much of the metaprogramming cleverness is lost.

However, if the metaprogramming could be kept simple and regular and visually striking, then it could be absorbed much more easily.  Think about ActiveRecord.  Maybe it doesn't matter so much how we say something, as long as we can make it visually recognisable and compelling, so that it promotes easy visual parsing.

I was almost giving all sorts of non-visual code reading now, and I was forgetting test code.  Test code is a conspicuous exception to what I have just said about visual parsing.  If a project has tests I prefer to read the tests rather than the project code.  Tests are better at capturing the intent of the code and the way to interact with it.  They also clearly capture the dynamics of instances, providing not only a compositional/structural view of code, but also the modes of interaction with the code.  However tests must be read and cannot be simply absobed using gestalt-reading.  Maybe that's because they tend to specify behaviour rather than structure...



Monday, April 03, 2006

Minimal Descriptions and Metaprogramming

My fellow socialite Pilu has opened a blog, Gurage, where he provides an introductive examples to Rails.  He uses a simple inheritance example describing a Guitarist and a Singer as being two subclasses of Artist.

While reading his code, that describes a Struct-like class (more an holder of attributes than an holder of behaviours) I thought back to a discussion that we had at the Ruby Social Club meeting about metaprogramming tricks.  My point was that through metaprogramming you can redefine the language in such a way that you can also provide stereotypical descriptions for classes and methods, so that you don't have to explicitly describe initializer, accessors, and so on.

For example, this code written by Pilu
class Artist
attr_reader :name
def initialize(name)
@name = name
end
end
could easily become something like:
Artist = Struct.new :name

This second form is no doubt more compact, but is it better?

Forget the fact that the full class definition already provides the 'space' to add in new methods and attributes. Assume that the code is done and you are simply reading it.  What is better? and why?

Something tells me that I would like the more terse and compact form, but somehow I still find that the first form has got something that the compact form lacks. I just can't put my finger on it.

Following on from Pilu's example I would like to have a compact formalism that allows me to say something like:

Artist defined by name

Guitarist is an Artist also defined by guitar
Singer is an Artist also defined by microphone

Using metaprogramming is not too hard to generate this kind of Minimal Descriptions, although they would probably look like this:

Artist = defined_by :name

Guitarist = Artist.also_defined_by :guitar
Singer = Artist.also_defined_by :microphone
 
I will leave the metaprogramming as an exercise for the reader :-D

The 'defined_by' is just wrapping a call to ' Struct.new', probably also adding a few extras such as a comparison operator and a prettier to_s method.  The 'also_defined_by' is a method that has been injected into the Class class.  It creates a new anonymous subclass, adding a few extra accessors and also overriding the initializer by adding some extra parameters.

We have seen how this is technically feasible, I just wonder if this is what we want. 

The standard way of doing things shows us explicitly that we are dealing with a class.  The 'class' and the 'end' words and the indentation highlight clearly a  chunk of code and identifies it as being a class, an important  concept within the narrative of our system.

The Minimal Description approach tries to hide away the whole concept of class.  It simply cares about concepts and meaning and it abstracts away a big body of knowledge.  The body of knowledge that is abstracted away  is that we are defining classes and that these classes are related by inheritance.  It is also assuming that we know that if something is defined by a certain characteristic, then this characteristic will have to be used when creating an instance of that concept.

What do you think?  Is this a rightful use of metaprogramming and of Shaping code After Language, or is it a blatant abuse of metaprogramming power?


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