onsdag, september 20, 2006

Dynamic Ruby power and static balance

Update: This post has been updated to explain, clarify and remove certain things that sounded like an attack on people that didn't agree with me, especially Austin. This was certainly not my intent when writing it. Added explanations will be highlighted with italic text.

Sir Bedevere
: And what do you burn, apart from witches?
Peasant 1: More witches.
Peasant 2: Wood.
Sir Bedevere: Good. Now, why do witches burn?
Peasant 3: ...because they're made of... wood?
Sir Bedevere: Good. So how do you tell whether she is made of wood?
Peasant 1: Build a bridge out of her.
Sir Bedevere: But can you not also build bridges out of stone?
Peasant 1: Oh yeah.
Sir Bedevere: Does wood sink in water?
Peasant 1: No, no, it floats!... It floats! Throw her into the pond!
Sir Bedevere: No, no. What else floats in water?
Peasant 1: Bread.
Peasant 2: Apples.
Peasant 3: Very small rocks.
Peasant 1: Cider.
Peasant 2: Gravy.
Peasant 3: Cherries.
Peasant 1: Mud.
Peasant 2: Churches.
Peasant 3: Lead! Lead!
King Arthur: A Duck.
Sir Bedevere: ...Exactly. So, logically...
Peasant 1: If she weighed the same as a duck... she's made of wood.
Sir Bedevere: And therefore...
Peasant 2: ...A witch!
(quotes from Monty Python and the Holy Grail, courtesy of IMDB)

My post announcing Ducktator seems to have stirred up a few emotions on Ruby-talk. Of course, most of this is my fault, by naming the library in such a frivolous way and not explaining the domains for its usage correctly. But on the other hand, there seems to be a general confusion about the concept of Duck typing, dynamic versus static typing, validation and other issues. Actually, I get a whiff of religion when my mention of Duck typing engendered such a diverse set of responses.

Of course, my reaction about duck typing was as religious. I see this is a general trap when discussing programming languages. The Ruby community is altogether very good at avoiding religion, which caused me to be quite startled when I found hints of it. Duck typing as a concept seem to be very loaded right now. I'm merely pointing this out as something that we should take care to be on the watchout for. Just as I will do from now on, I suggest people in the Ruby community should try to be as objective as possible, when discussing this.

And everyone and their aunt seem to have different opinions on what duck typing really is. It's all quite fun, actually, except for the fact that it misses the point. I should have avoid mentioning ducks. I should have avoiding saying anyting at all about typing, since that isn't the point. And I bloody well shouldn't have used the class-validator in my example. Well, done is done. And this post won't be about that. Just the next paragraph.

The Ducktator disclaimer

I won't mention the words duck typing from here on. I would change the name of the project if it wasn't so damn hard in RubyForge. But what I want to explain is this. Ducktator is about validating things. But not everywhere. You shouldn't use Ducktator at those places where you have one or two checks for something in an object. You should really only use it at the borders of your code. The borders where you you will receive complex objects. Really complex objects where a method_missing won't tell anyone anything useful at all. The use case I had in mind when writing the library was for RubyGems, when the YAML spec for a Gem has been loaded, to check that the important parts actually have what it takes to get into the source index. Since I managed to break RubyGems this way, I feel that this kind of validation can be really important. Once again, this is validation of live Ruby objects. Nothing else. You can check practically anything you want, but the easiest examples have been about each, class and respond_to. Hope this clarifies things a bit.

I removed the entire paragraph about typing. But my recommendation still stands; if you find formal types in programming languages interesting and/or confusing, read Programming Language Pragmatics, and you will be enlightened.

The main point

The reaction to my possibly improper use of the term Duck typing engendered a very strange response, which I hadn't expected. Of course, I realize that this is a very obvious community effect. Since Duck typing is one of the trademarks of the Ruby community, it also means everyone has opinions on it, and more importantly feel the need to defend it as soon as some threat is perceived. Steve Yegge has written lots and lots about what language religion is really about, and I feel that this is an extension of that issue, so I won't write more about it here either. You can find more in many of this excellent Drunken Blog Rants.

Finally. Balance is what I'm after. One person (Austin) said that the d**k t****g philosophy (I had written the word 'issue' here. That seems to have been misinterpreted. I blame that on my poor grasp of English, since my mother tounge is Swedish. =) is about TRUST. That you should trust the caller of your library to read your documentation (which - obviously - is perfect), and supply the correct objects. This isn't too much to task if your docs are up to notch. And if the caller is the same one that will suffer if he mishandles your library. But trust isn't enough when you're at the borders. When talking to other languages through shaky serialization systems. When talking with clients that possibly could be hostile. (Yes, in this case setting $SAFE helps, but it doesn't go all the way). (Sandbox is - or will be - a good alternative here, but I still see places where object validation is a better solution.)

Further, Austin responded in his blog post that he thinks I have 'set up a false dichotomy here: people who are for duck typing as trusting your caller are against validation'. This wasn't my intention. Actually more the other way around. I am for duck typing, in most places. What I'm saying is that no solution is perfect at all points in your code and duck typing is good fit in many, but not all. Further, the next paragraph clarifies my wish for balance.

What I'm saying is, most of the time you won't need it, but in some cases, some kind of interface validation really helps a lot. I know the so called dynamic community doesn't like to hear this. But what is so dynamic about failing without control? (The arguments I heard about letting code fail when the method isn't there sounded very much to me like failing without control. That was my interpretation of the argument that you don't need to use respond_to? for duck typing.) I know that I, as a developer isn't infallible. I make mistakes. Most of the times I am in control of all my objects, but there are times when I'm not. For example, there are situations where I develop smaller applications for other (non-programmers) people. I like to create configurations and rules in YAML for these projects and leave the client in charge of configuring the application. But, what if he/she/it makes a mistake? Using the 'other' way, I would fail when trying to call protocol on something that should have been an URI, but wasn't because the person made a typo and put an illegal character inside the URL. Will that message help the person doing the configuration? Should you wrap your calls in rescue's all over the place and give the same explanation? Should you trust that the (non-programming) client should be able to read your RDoc and figure out that a method (which I bet you didn't name get_uri_from_yaml_configuration) failed because of something they did in the configuration? I believe not.

What I'm really ranting about is balance. There needs to be a balance between checking and laissez-faire. In most places, just calling the method is fine. In other places it's appropriate to check with respond_to?, in some cases you need to check the class. We're programmers. We are supposed be good at judging which technique to use where. Yes, Ruby is dynamic language. Yes, Ruby is very easy to learn. Yes, Ruby makes most stuff very easy on you. That doesn't mean you should stop thinking. It doesn't mean you should be lazy. We are programmers, and we should be able to adapt.

One more time. Balance. Balance. Everywhere. And I do love the Ruby community. It is the best. Even though people get mad at each other, we can solve our differences. I'm proud of being a part of it.

2 kommentarer:

Damian sa...

Well the reaction seemed quite lively, but it wasn't until I read this reply that I thought you had a substantial point.

I would have replied to it directly, but apparently one has to 'log in' somehow :-( Nastiest thing I've seen in the ruby community.

Pick 3 Turbo Player sa...

Nice blog!

If you get a chance, check out my site: Pick 3 Turbo Player