“!” and “?”: Understanding One of Ruby’s Coolest Naming Conventions

tells me, the person reading your code, that this method (also called predicate method) will return a boolean-like value (truthy or falsy — it does not have to be a strict boolean) and it should not yield side effects (you can read more about side effects here) or alter the object’s state.

We have some out-of-the-box examples in Ruby like:(Which answers our first question: it’s a Ruby convention!) ┐( ̄ヮ ̄)┌With that in mind, you can implement situations like this one:See how nice to read that last line is!.(•̀ᴗ•́)و ̑Bang!The exclamation mark is… a bit more complicated.

Also called “bang methods”, despite being very widespread there’s not much consensus about its use.

That being, I’m going to enumerate a few situations where you could use a “bang” in one of your methods.

So, if your method:Performs a destructive action (like deleting something from a database);Has side effects (writes to a file, calls for a user’s input, modifies non-local state);Modifies the original object in which is being called;Has potential to raise an exception;Then use the bang!But the most important tip is this one:If you have a method that is marked with a bang at its end, then a version without it should also exist.

As my noble friend Thiago Araújo Silva stated to me:The bang should be used exclusively as a more dangerous version of an already existing method.

Therefore, as a rule, methods should not be written with the bang.

But that convention only concerns the Ruby core language.

Take the following code as an example:The merge method returns a merged (“Ohh really?.(⊙_☉)”) version of the hash but keeps the original object intact (the return value and the original object are different objects), while merge!.actually modifies it.

One could even say the “bang version” is an “overheated version” of the method, like it says “I AM DANGEROUS!” or “I CAN RAISE AN EXCEPTION!!” or “I’LL FLIP THIS TABLE!!!.(ノಠ ∩ಠ)ノ︵ ┻━┻”.

As the last drop of wisdom and advice, I would say this:When working on a project, try to keep up with the project’s convention.

There is a variety of situations where you could use this to write your methods, so it’s very important to keep your codebase consistent.

Keep that in mind ʕᵔᴥᵔʔA special caseRemember that I said predicate methods should NOT change the object’s global state or yield side effects?.Well… In Ruby’s standard library there’s a class called Set: “[It] is a hybrid of Array’s intuitive inter-operation facilities and Hash’s fast lookup”.

In any instance of a Set, you’ll find two methods: add and add? .

Let’s check this nice gist below:“setentou?” *Pretty crazy, right??Actually, it’s also pretty cool in terms of usability, despite being a bit inconsistent with the convention.

Remember: the implementation must make sense primordially within the project’s domain (in this case, the Set domain).

The add?.method is meant to be used like this:I really like guacamole…The point is that Set is a data structure for unique keys!.So, instead of having to ask if you can add an item and then add it, you can do these two operations in one fell swoop and avoid a conditional.

And I think that’s neat!.(̿▀̿ ̿Ĺ̯̿̿▀̿ ̿)̄.

Some bits of history“Aliens…” — That guy with funny hairI have already worked/studied a few other languages in the past, and I can say that this naming pattern is NOT that common.

I went curious about where these came from and decided to dig a bit deeper to the roots of it.

As far as I can say, the inspiration for the ?.suffix came from the concept of predicate functions.

In mathematical logic, they are usually defined as functions bound to return a boolean value, also called Boolean-valued function (the function’s domain is a true/false or 1/0 set).

The usual way I’ve seen languages dealing with this concept is by prepending an is_/Is to the beginning of method names, or even a _p / P (standing for “predicate”).

Now trying to find more direct influences, I went no far than Ruby’s about page:[Ruby’s] creator, Yukihiro “Matz” Matsumoto, blended parts of his favorite languages (Perl, Smalltalk, Eiffel, Ada, and Lisp) to form a new language […]Now I had somewhere to start looking!.I have not much experience in most of those languages, but enough to tell that:In Perl, predicate functions end with a capital “P”;In Ada, “Predicates” are like constraints for types;Eiffel and Smalltalk have no conventions for this.

But Lisp, on the other hand (more specifically Scheme,) is exactly what we’re looking for.

The syntax is pretty much the same as Ruby’s, so that’s probably where it came from.

You even have the !.suffix to convey the idea of a mutation:Wrapping upSo, there you have it!. More details

Leave a Reply