0

I am seeing this type code in Ruby often but I don't understand it. I am talking about the "?" and "!" character. For the examples below, are they being used as just part of the function name or is it some kind of operators ?

unless n.is_a? Integer

prime_array = [] if prime_array.nil?

myarray.sort! 
Marek Lipka
  • 48,573
  • 7
  • 81
  • 87
tadpole
  • 1,163
  • 7
  • 17
  • 27
  • Ok thank you Meagar and Marek. My head is clear :) – tadpole Aug 28 '14 at 14:54
  • Don't forget to mark one of answers (preferably meagar's one, since it's much more comprehensive than mine) as accepted. – Marek Lipka Aug 28 '14 at 15:00
  • I guess that they down voted you because this topic is easy. Well, without knowing proper names for `!` - exclamation marks (or in Ruby's case: *bang methods*) and `?` question mark, google won't help you. Well, you can find some names in the English wiki. And I've looked up at few posts and I've found Matz' post: https://www.ruby-forum.com/topic/176830#773946 – Darek Nędza Aug 28 '14 at 21:45

2 Answers2

4

Ruby's syntax allows you to postfix a single ? or ! to your method names (both or more than one of each is invalid).

This is to support a couple of deeply ingrained conventions:

method?:

A method that returns a boolean and doesn't modify its receiver's state should use a ?. For example, if you want to "ask" whether a container is sorted, you might use my_obj.sorted?. If you want to "ask" whether a container is empty, you might use my_obj.empty?. Neither of these methods would modify their receiving object's state. See String for many examples of ? methods being used to interrogate an object without modifying it, such as start_with? and end_with?.

method!:

A method that has a ! at the end destructively modifies its objects state. By extension, when a method might destructively transform an object's state, there are often two versions of the method provided, with and without a !. In the case of an array, you might have a pair of methods called sort and sort!. sort will return a copy of the array, in sorted order, without modifying the original copy. After calling sort, you will have two copies, including an unmodified version of the original. sort! however, will sort the array in-place, overwriting the original array.

Again, referring to String, we have methods such as capitalize which returns a capitalized copy of a string, and capitalize! which capitalizes the string in-place:

x = "what"
y = x.capitalize
puts x # "what"; x is unchanged
puts y # "What"

x = "what"
y = x.capitalize!
puts x # "What"; x is changed in-place
puts y # "What"

It's worth noting that Rails has its own conventions for the semantics of !. In Rails, a method that can fail (such as a database write) will typically return true or false. Rails uses a ! to indicate that the method should fail with an exception, instead of a false return value. For example, my_record.save will return false on failure; my_record.save! will raise an exception.

Community
  • 1
  • 1
meager
  • 209,754
  • 38
  • 307
  • 315
  • 1
    method!: it not just something that will modify the objects state, it is generally used when there are unexpected side effects, not just modifying the caller. Other examples: exit! which does not run finalizers like exit does – Jeff Price Aug 28 '14 at 15:16
  • I should add to my comment, the rails example in which an exception is thrown instead of "true/false" is another example of an "unexpected" side effect that warrants the ! at the end of a method. Think of it as a "warning" that you should check the documentation to see what is special about this method before using it. – Jeff Price Aug 28 '14 at 17:47
  • @JeffPrice In my opinion (that what I have read) `!` (bang) suggest that this method is dangerous. I think that modifying the caller, `exit!`, other side effects are *dangerous* – Darek Nędza Aug 28 '14 at 21:24
  • Well, to be pedantic, Ruby allows method with more than one `?` or `!` (or other letter than a-z, A-Z, 0-9) `class A; define_method 'true?!' do; puts 'yes!'; end; end; a=A.new; a.send 'true?!' # yes!` – Darek Nędza Aug 28 '14 at 21:31
2

These are parts of method names. Ruby convention is that methods returning boolean values are named with ? on the end, while possibly harmful methods are named with !.

meager
  • 209,754
  • 38
  • 307
  • 315
Marek Lipka
  • 48,573
  • 7
  • 81
  • 87
  • Ok, I understand the "?" now. I am still not sure about the "!" though. I assume that the "!" does not stand for the NOT operator. Are you saying that if method has the "!" by convention means that it can do something harmful ? – tadpole Aug 28 '14 at 14:45
  • "! methods" often mutate the object they are called on. – max Aug 28 '14 at 14:48
  • I'm saying that if method has `!` on the end means by convention that it can do something harmful. But `!` is also operator, if you put it in front of some expression, it will return its negation: `!false #=> true `. – Marek Lipka Aug 28 '14 at 14:48