10 things I didn’t know about Reddit
So I woke up this morning and saw that 7 people had saved my method_missing post to delicious. How can this be? I wondered. Who even reads this blog? We checked our stats and saw a bunch of pageviews, because someone linked to us from Reddit (No, we didn’t submit ourselves. We have two small children, here, people, we don’t have time to go around flogging our blog under pseudonyms. We barely have time to flog … never mind). Anyway, then someone else commented, quite correctly :
This isn’t “10 things you should know”. It’s ten paragraphs, each assigned a number for no reason other than the fact that “X things…” lists are better reddit/digg-bait.
It’s funny, because I had a whole paragraph in the original draft about precisely that. I went back and forth about calling the post 10 things, and I went back and forth about numbering the things, and I dithered about the numbering, and the post took me three hours to write and I had other things to do, so I finally decided that the paragraph about whether to call the post “10 things…” was gratuitous meta-blogging, took it out, and left the numbers in.
I’ve never written a 10-things post before. I’m not a ‘pro-blogger’. I do sometimes read posts like ‘10 tips to publicize your blog’ though, because I need money, and therefore I need work, and so one way I can try to drum up Ruby on Rails work is to try to contribute to the community in some useful way, and if you’re going to contribute it helps if people are reading you, at least a teeny bit. Etc. So what the hell, I thought, I’ve been meaning to write about method_missing for a while, I’ll see if I can do it in a 10 things format.
So I wrote out all my thoughts about method_missing, and it looked nothing like 10 things. I reorganized it to make the major points more obvious. I took out some stuff that didn’t belong. I revised. Still more of a meander than a 10 things. More revising. Better structure, but not 10 unrelated things; more like 10 points, each leading to one another. (Hmm, an essay. But the internets don’t like essays! ) Okay, I did my best, I thought, time for bed.
And then I wake up and there we are on reddit, with the harsh light of a tiny amount of publicity showing me up as an obnoxious blogging publicity-hound.
Oh well. 7 people thought the post was interesting and useful enough to save to delicious, so that’s something.
And no, I don’t really have a list of 10 things I didn’t know about Reddit. Just one: I had no idea how successful a tactic it was to call something “10 things…”. Beyond my wildest dreams. Though I don’t think I’ll be doing it again anytime soon. Go ahead, reddit readers, flame away!!
10 things you should know about method_missing
[update, 9:27 a.m., 8/1/2007: welcome, reddit readers. annoyed at me for calling this post “10 things”? Well, then you’ll really hate me after reading this post!]
1. method_missing is a Ruby kernel method and everyone should know about it.
2. Rails implements some of its funkiest magic with method_missing. When you ask your model to find_by_freaky_column_name, and it does so, that’s because ActiveRecord::Base overrides the kernel’s method_missing method.
3. method_missing is the method of last resort. When you send a message to a Ruby object, Ruby looks for a method to invoke with the same name as the message you sent. (There are a bunch of different ways to send the message, but the most common one is just obj.method_name. But you can make the fact that you are sending a message explicit by using obj.send(:method_name)). First it looks in the current self object’s own instance methods. Then it looks in the list of instance methods that all objects of that class share, and then in each of the included modules of that class, in reverse order of inclusion. Then it looks in that class’s superclass, and then in the superclass’s included modules, all the way up until it reaches the class Object. If it still can’t find a method, the very last place it looks is in the Kernel module, included in the class Object. And there, if it comes up short, it calls method_missingYou can override method_missing anywhere along that method lookup path, and tell Ruby what to do when it can’t find a method.
4. Sometimes people use method_missing to implement some default behavior they want to occur; more often they seem to use it as a kind of method factory or dispatcher. They have a class or module that they want to have many methods that do generally the same kinds of things, they’re not sure in advance which methods people will actually want to call, or there are so many of them, and they’re all so similar, that it seems like a waste to implement them all by hand. So they just say, okay, if someone gives me a method that doesn’t exist, I’ll assume that they’re trying to do this general kind of thing, and I’ll make them a method based on their name that does the thing they probably want it to do.Sometimes they make a new method and add it to the class (factory); sometimes they just do what needs to be done in method_missing itself (dispatcher).
5. Basically, method_missing is one of the features of Ruby that make it remarkably easy to create your own DSL for fun and profit. DSLs are Domain Specific Languages, which, if you didn’t know — and of course, dear reader, you did, because you are oh-so-up on all the oh-so-fashionable programming paradigms, are the big thing that Martin Fowler is talking about a lot these days.
6. Here’s the kernel’s method_missing implementation. It’s in C, so I have no freakin’ clue what it’s doing, but I know what the result is: a NoMethod error:
irb(main):227:0> "thingy".invoke_method_missing_for_demo_purposes("arg", "other arg")
NoMethodError: undefined method `invoke_method_missing_for_demo_purposes' for "thingy":String from (irb):227
7. Now here’s Jamis Buck showing us how ActiveRecord::Base overrides method_missing. It’s a long but fascinating article that takes you step-by-step through some Rails source code. Go look at it now.
8. method_missing is said to be slower than calling an actually-already existing method, unsurprisingly, given that it’s by definition invoked only after Ruby’s looked everywhere else for your method. The speed issue may or may not matter for your intended use, and my impression is that it usually doesn’t. #{usual disclaimer about benchmarking, using profilers, and not prematurely optimizing your code.}
9. method_missing can also be a bit opaque to users of your code, since dynamically created methods are, of course, not documented in the API.
10. The use of method_missing falls under the general technique of metaprogramming, which is a big deal in Ruby, and not something ordinary folks ever fool around with in many other languages (like Java). At least, I never fooled around with it in Java. But hey, what do I know? What is metaprogramming? C’mon, people, it’s right up there with DSLs in the list of things the kewl kids know. But actually, it really is pretty cool, and it really is pretty much the way Ruby works. And it’s not as difficult as (but waaaay more useful than) say, Lacan, despite the poststructuralist-sounding name and the fact that the metaprogramming wikipedia article makes it sound very fancy.
Ignore the wikipedia article, listen to _why, in a discussion of method_missing: “I don’t think the idea here is to save memory or speed. The idea behind metaprogramming is to teach Ruby your conventions and let it do some guessing, in order to save you some code.”
Don’t trust that _why and all his chunky bacon? Here’s David Black, equally reassuring:
One of the great accomplishments of Ruby is that its object and class model bring about a wonderful unity and simplicity. Even things that might seem like they should be hard or obscure are actually very transparent, once you have the hang of how the model works.Unfortunately, there’s a trend toward drawing an increasingly sharp line between regular programming and “metaprogramming” in Ruby discussions, where metaprogramming is understood to mean… well, I’m not sure what it’s understood to mean, the way it’s getting used in connection with Ruby, and that’s the problem.There’s no natural separation between programming and metaprogramming in Ruby, and no reason to make life harder by breaking them apart. The thrust of Ruby’s design is to dissolve complexities, so that even things that appear to be “wizardly” or full of “dark magic” actually make perfect sense in terms of a relative small number of underlying language principles.
So here’s your takeaway #{max gagging sound}: method_missing is cool. It’s metaprogramming. It’s used to save programmer time and typing, and to make DSLs or provide default behavior. Most famously in ActiveRecord dynamic finders. Metaprogramming is not scary, and method_missing, like other cool Ruby features, may or may not float your boat. That’s cool, either way.
_why says: “I never use method_missing. Maybe twice. And both times I didn’t use it, regretted it, forcefully ejected the code from a moving vehicle, shed nary a tear.” Then he goes on to enumerate some of the very cool ways he’s seen method_missing used elsewhere, in non-_why code.
So: know it, love it, use it, hate it, kill it, eat it, break it, think it. As they say at Ari’s preschool: “Have fun, be safe, and USE YOUR IMAGINATION!” Matz wants you to.
Rails Ninjas We Are Not
The other day I responded to an ad looking for Rails Ninjas. A very nice guy called me up to talk about his startup. He asked me to talk about our rails skills. Would I describe myself or Max as a rails superstar? I said “look, we’ve been using rails since March. We are not rails superstars.”
Why did I respond to an ad asking for Rails superstars when I make no claims to be one? Because there are many ads looking for Rails superstars and there are not enough to go around. There certainly aren’t undiscovered rails superstars around. We’re not talking supermodels here. You don’t take an ordinary Romanian peasant and turn her into a rails superstar overnight with a nice haircut and a manicure . Rails superstars have blogs and open source projects and debates about the importance of symbols on the rails-core mailing list. They have histories.
Me and Max, we don’t yet have a history with Rails. We are not superstars.
And yet, we are not script kiddies. Rails is full of amazing magic. How do instance variables set in the controller end up as instance variables in the view? Who knows? And who cares? Script kiddies don’t care. It’s automagically terrific, and that’s all they need to know.
If you look at the source code, though, you fall down a rabbit hole. You discover that Ruby itself has a method called instance_variable_set (be sure to check out the documentation on that!), that you can call on _any_ ruby class. How utterly transgressive! You can just shove whatever you feel like in anyone’s class at any damn time you please. You can make brand-new methods on the fly, when you need them, by using method_missing to make a new method whenever you call one that doesn’t yet exist. Amazing feats! And not implemented in secret or in C or something that isn’t any fun to look at and that there’s little hope of your ever being able (or particularly wanting) to do similar things yourself. All the magic is just hanging right out there for everyone to see. And it’s all just part of Ruby, a cute little language that’s fun to code.
And you think, yes, I can do this! Someday I too may tackle the continuation koans.
But not just yet.
