This is a read-only archive!

Bang!

In Scheme, an exclamation point (aka "bang") on the end of a procedure name indicates a procedure with side-effects e.g. a destructive procedure or mutator. This is only a naming convention for procedures and isn't understood or enforced by the language.

In Ruby you can also have an exclamation point on the end of a method name, and again it's only convention for programmers and means nothing for the language, but it's far less clear what a bang-method means in Ruby even by convention. A Google search reveals that lots and lots of people think it means something similar to Scheme: That a ! method changes the value of the calling object. On the other hand, David A. Black wrote a good article about his interpretation of !-methods in Ruby as nothing more than "the more dangerous of a pair of methods with the same name" for some value of "dangerous".

Well, not all methods that change the value or state of the calling object end with a bang. Array#pop and Array#push are obvious examples, but there are plenty of others. What about File.close? Thread.run? All of the []= methods? It makes sense that not all destructive methods in Ruby end in !. In Scheme or some other language where side-effect-free functional style is encouraged and expected, you need to flag methods that edit objects. If I "push" something onto a list in Scheme I probably won't expect my original list to be modified or destroyed in the process, unless the procedure was called PUSH!.

So given that not all mutator methods end in ! in Ruby, do all methods that end in ! change the caller object in-place? Almost. There are only 68 standard methods that end in !: About half of them are String and Array methods and the other half are a mix of things. Mostly all of those methods do some kind of in-place edit of the caller object. Interesting though is Bignum#power! which does NOT edit a Bignum in-place. Also interesting is Thread.terminate! which does edit the state of a thread (by killing it); but Thread.terminate ALSO kills a thread; the only difference between the two is how the thread is killed (whether it runs ensure blocks or not).

Outside the standard methods, there are things like OptionParser.parse! which destructively edits not itself, but another object (ARGV). And this seems to make plenty of sense to me, in spite of not being entirely consistent with other use of !.

Well then, is a !-method always simply the more dangerous of two methods with the same name? Usually. But oops, there is no Bignum#power to go with Bignum#power!.

So this ends up being somewhat confusing. What does ! in method names in Ruby actually mean? There doesn't seem to be a consistent answer, other than "Hey, this method does something that may be unexpected in some way".

Given that it's inconsistent, is it the case that there is a formal, strict, true definition of what ! means but that a handful of methods violate the definition? You could say that, though I'm not sure where that definition would come from. Maybe from the decree of Matz? Or maybe from the meaning of the convention in Scheme? Clearly Ruby ripped this convention off of Scheme.

But a convention is by definition simply a common usage of something. Convention allows for exceptions; if it didn't, then it wouldn't be a convention, it would be part of the syntax of the language. So maybe ! in Ruby means whatever the majority of people decide it means. Or maybe not.

December 01, 2007 @ 10:25 AM PST
Cateogory: Programming
Tags: Lisp, Ruby, Scheme