The Dynamic Language Advantage: A Concrete Example
Not too long ago, someone asked me to explain the fundamental differences between static languages, such as C# and Java, and dynamic languages, such as Ruby and Python.
Although I knew that duck typing and not resolving method references until runtime allowed for some nifty metaprogramming tricks that translated into not having to write as many lines of code, I was not able to provide any concrete examples of how this was done. This left both me and my friend feeling unsatisfied with my explanation.
Although learning about something at a high level through books, blogs, and podcasts can be useful, I often find that it tricks me into thinking I know more about something than I actually do. I’ve just had way too many experiences where I thought I understood something only to be proven wrong when I finally had the opportunity to roll up my sleeves and tackle some concrete examples and problems.
This is why I have recently been on the look out for some more concrete examples of how dynamic languages allow for some nifty feature that just aren’t possible in static languages (or at least too difficult to be feasible).
I finally found a good one this last week while reading about Dynamic Finders in the book Agile Web Development With Rails. These are convenience methods provided by Rails that allow you to query on various columns by simply following a naming convention for methods that concatenates Find_By or Find_All_By with the column names you want to filter on.
So, instead of having to create and implement a method like this (example from Castle’s Active Record):
1: public static Card[] Find_By_CardType_And_ExpirationDate(int cardTypeId, DateTime expirationDate)
2: {
3: return FindAll(Expression.And(Expression.Eq("CardTypeId", cardTypeId),
4: Expression.Eq("ExpirationDate", expirationDate)));
5: }
6:
7: ...
8:
9: Card[] cards = Card.Find_By_CardType_And_ExpirationDate(cardTypeId, expirationDate);
All you have to do is make the call to the non-existent method that contains your column names and Rails will dynamically generate the method for you.
1: @cards = Card.find_all_by_cardType_and_expirationDate(cardTypeId, expirationDate)
How does this work?
Unlike with static languages, Ruby doesn’t require that this method actually exists at compile time. Instead it just throws a MethodMissing exception at runtime if the method you called doesn’t exist and then allows you to react to this condition by simply defining\overriding the required method_missing signature in your class.
In order to provide Dynamic Finder functionality, Rails uses something like the Regex logic below to parse the method name that was passed in to the method_missing override and then use the resulting tokens to dynamically generate the method and its implementation, “spot weld” it onto your class, and then execute it.
1: def method_missing(method_id, *arguments)
2: if match = /find_(all_by|by)_([_a-zA-Z]\w*)/.match(method_id.to_s)
3: # find...
4: elsif match = /find_or_create_by_([_a-zA-Z]\w*)/.match(method_id.to_s)
5: # find_or_create...
6: else
7: super
8: end
9: end
Neat, huh?
I found this example particularly compelling because I am working with both frameworks right now and so far find Castle’s implementation to be remarkably similar to Rail’s Active Record even though it was created using a static language (C#).
The fact that Dynamic Finders aren’t available in Castle’s Active Record and that they are implemented by a decidedly dynamic feature leads me to believe that this was one of the areas that dynamic languages outshines static languages. However, I am a self-avowed newbie in this area, so I welcome anyone with a deeper knowledge of either framework to correct me if I’m wrong.
I would also love to hear about any other concrete examples of metaprogramming magic that is made possible (or much easier) by a dynamic language feature.
If you’re interested in learning more about dynamic languages, then I highly recommend Steve Yegge’s recent blog post, Dynamic Language Strike’s Back. It’s a rather lengthy transcription of a recent talk he did at Stanford on the topic, but it addresses some questions I had about dynamic languages in terms of tooling, performance, and maintainability in some very novel and comprehensive ways so it was well worth the reading investment.
Popularity: 20% [?]
Comments(21)


[...] The Dynamic Language Advantage: A Concrete Example (Russell Ball) [...]
This is where we can lean on Ayende for some C# magic. He created NHibernate Query Generator (NQG) which basically allows you to do this:
_repository.FindAll(Where.CreditCard.CardType == cardType && Where.CreditCard.ExpirationDate == expDate);
The generated Where class does all kinds of heavy lifting to give you a strongly typed query experience. Each expression generates a DetachedCriteria that can easily be passed to NH/AR.
But the ruby magic is still cool, don’t get me wrong
I’m not familiar with Castle’s Active Record, but can appreciate what Ruby does.
One thing I like about some of the dynamic languages is the concept of truthiness.
In JavaScript all these values evaluate to false:
– 0 – The number zero
– “” – The empty string
– NaN – A special value meaning Not a Number
– null – The empty value
– undefined – The undefined value
Using Truthy and Falsy values results in fewer lines of code.
@Ben – Thanks! I was hoping there was a more fluent style of creating NHibernate criterion objects. I’ll definitely check it out.
Even so, I must say that the Rails way still seems much more concise.
What most dynamic language advocates don’t see is, that
Card.find_all_by_cardType_and_expirationDate(cardTypeId, expirationDate)
is no more safe than
Card.find(”all_by_cardType_and_expirationDate”, cardType, expirationDate);
which doesn’t look as nice with the ( and ” but is close enough. And possible in every static language.
So, I don’t think your argument holds.
Peace
-stephan
Easy in C#, trivial in most statically-typed functional languages. Without the threat of conflicting monkeys. Most meta-programming is just a sloppy substitute for higher-order functions and modern type systems.
The Rails interface is more concise than the C#, but that’s mostly because the C# one is designed to work on general predicate functions – it can express a wider range of conditions.
@Adam: how does the person reading your code understand its intention when a value might potentially be any of four of these? They are not Booleans. If you use them in your code as if they are, it’s going to bite you one day.
There are many advantages to dynamic languages, but I think you did yourself and dynamic languages a disservice here – this is indeed a very lame example.
I find Card.find_all_by_cardType_and_expirationDate to be needlessly painful. Much more intuitive if you can wrap a DSL around it. As recent innovations in .Net (lookup LINQ) and even in the JVM (look up Scala) show, it is quite easy now to write very expressive code using a custom DSL in a statically typed language – just as you could in a dynamically typed language like Ruby.
In this example you move the code from the Card.find_all_by_cardType_and_expirationDate declaration to the method_missing method.
The tip attempt to save coding rows and delegate to method_missing a wrong role.
It is not up to such a method to decide the matter of the query, it is a method to handle runtime errors as ‘method missing’, so it is conceptual misleading. Further, static languages as Java have a easy reflection API.
BTW, good post in order to raise the argument.
@Greg the person reading the code would understand the conventions for truthiness just as they would understand the conventions for type coercion, prototypal inheritance, and JavaScript’s classless nature.
Truthiness won’t bite you if you understand the intent. Alternatively the author could throw their training wheels back on (program for the lowest common denominator) and start explicitly comparing values.
[...] http://www.caffeinatedcoder.co.....e-example/ [...]
@Adam:
Exactly. You’ve hidden the intent. You should never write “if x” when you mean “if x!=0″. It doesn’t matter if _you_ think x could never be NaN, null or undefined – once you’ve written it, it’s not your code anymore.
Code is for reading and modifying. Any chump can write code for a compiler.
@Ishaaq:
I agree with you about this article, why don’t _you_ give a concrete example of the many advantages to dynamic languages? Everyone else I’ve seen that’s tried has fallen flat on their face.
@Greg Truthiness is a fundamental part of the language. The intent could be hidden if you don’t understand the language.
Sure, any monkey can hack their way to comprehension, but developers should understand the fundamentals of the language they’re using before they start reading and maintain code.
BTW JavaScript is interpreted (not compiled).
@Adam: BTW Javascript is somtimes interpreted (last generation browsers), sometimes compiled (e.g. Rhino) and somtimes just-in-time compiled (e.g. SquirrelFish, Tamarin).
Peace
-stephan
@Stephan, I am aware of those cases, I was generalizing that the majority of JavaScript is interpreted not compiled – thanks for the correction.
@Adam: When you know there are potholes you’re able to avoid them, but that doesn’t make it a good road. Even experienced drivers will still go more slowly and have less attention to spare for larger-scale navigation.
Honestly I think this is a not so good example. First of all using exceptions for flow normal control is not such a great idea. Then you hardcode database schema information in method names (which don’t exist).
At this point you don’t have any advantage over writing plain SQL and that would be a faster solution. Generating the methods to access the DB over and over again in a busy application is a performance nightmare. No wonder Rails applications have scalability issues (i hear).
In the end comes the problem of readability and maintainability. The logic is not in the proper method, it gets generated at runtime (debug thrill?) and it is not so easy to read. Basically it hides the intent.
On the other hand congratulations for trying to find advantages to dynamic languages. Not many people even try to justify their believes.
But the use “method missing” is a common Ruby pattern for metaprogramming… is pretty much a straightforward example of Ruby use
@Gabriel,
Agreed, in order to make a compelling comparison of dynamic vs static languages I think we need to dig into the application level. Then we could contrast the different typing systems, object manipulation, and inheritance mechanisms, but since both types of languages are suited for different problem domains it would be difficult to do the comparison.
[...] A concrete example of The Dynamic Language Advantage [...]
I love the great insight!,
informative post, keep it up.,