101

Sometimes I see methods in Ruby that have "?" and "!" at the end of them, e.g:

name = "sample_string"
name.reverse
name.reverse!
name.is_binary_data?

I was wondering what their purpose is? Are they just syntax sugarcoating?

Timur Shtatland
  • 7,599
  • 2
  • 20
  • 30
itsaboutcode
  • 21,936
  • 42
  • 103
  • 153
  • 2
    Possible duplicate of [Why are exclamation marks used in Ruby methods?](http://stackoverflow.com/questions/612189/why-are-exclamation-marks-used-in-ruby-methods) – Stewart May 13 '17 at 22:40

5 Answers5

162

It's "just sugarcoating" for readability, but they do have common meanings:

  • Methods ending in ! perform some permanent or potentially dangerous change; for example:
    • Enumerable#sort returns a sorted version of the object while Enumerable#sort! sorts it in place.
    • In Rails, ActiveRecord::Base#save returns false if saving failed, while ActiveRecord::Base#save! raises an exception.
    • Kernel::exit causes a script to exit, while Kernel::exit! does so immediately, bypassing any exit handlers.
  • Methods ending in ? return a boolean, which makes the code flow even more intuitively like a sentence — if number.zero? reads like "if the number is zero", but if number.zero just looks weird.

In your example, name.reverse evaluates to a reversed string, but only after the name.reverse! line does the name variable actually contain the reversed name. name.is_binary_data? looks like "is name binary data?".

jtbandes
  • 104,858
  • 34
  • 217
  • 242
  • 22
    One important note is that you should only have a bang method if you also have a corresponding non-bang method. The bang is used to distinguish the "more surprising" version of the method from the "less surprising" one. If you have only one method, then there's no need for a distinction, and you shouldn't name it with a bang. See `Array#clear`, for example. It clears the array. Clearing the array naturally mutates it. There's nothing surprising about that, the name already makes it clear, therefore: no bang. See https://www.ruby-forum.com/topic/176830#773946 . – Jörg W Mittag Aug 28 '14 at 22:37
  • 2
    Adding to what @JörgWMittag stated, according to the [Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide#dangerous-method-bang): The names of potentially dangerous methods (i.e. methods that modify self or the arguments, exit! (doesn't run the finalizers like exit does), etc.) should end with an exclamation mark **if there exists a safe version of that dangerous method**. – Tod Birdsall Jan 07 '15 at 21:38
  • 2
    Beware, this isn't always the case. For example, Ruby Array#concat http://docs.ruby-lang.org/en/2.0.0/Array.html#method-i-concat. Where you can get burnt badly is something like MyActiveRecordModel.column_names.concat(...). Instead you must clone it before doing the concat. – wintondeshong Aug 26 '16 at 13:59
16

Question mark indicates that the method returns boolean. Already answered here:

What does the question mark operator mean in Ruby?

The bang indicates that the method acts on the object itself. Already answered here:

Why are exclamation marks used in Ruby methods?

Community
  • 1
  • 1
Bill
  • 824
  • 6
  • 21
8

In Ruby the ? means that the method is going to return a boolean and the ! modifies the object it was called on. They are there to improve readability when looking at the code.

J Lundberg
  • 2,013
  • 1
  • 19
  • 22
5

In contrast to the – I suppose – majority of programming languages ...

Ruby, methods are allowed to end with question marks or exclamation marks.

By convention, methods that answer questions (i.e. Array#empty? returns true if the receiver is empty) end in question marks.

Potentially “dangerous” methods (ie methods that modify self or the arguments, exit! etc.) by convention end with exclamation marks.

From: http://www.ruby-lang.org/en/documentation/ruby-from-other-languages/, Section Funny method names

Community
  • 1
  • 1
miku
  • 161,705
  • 45
  • 286
  • 300
1

Beware, this isn't always the case. Take for example, Ruby Array#concat http://docs.ruby-lang.org/en/2.0.0/Array.html#method-i-concat.

Where you can get burnt badly is something like MyActiveRecordModel.column_names.concat([url]). Later calls related to MyActiveRecordModel will try to look for a column of 'url' for MyActiveRecordModel and throw.

Instead you must clone it before doing the concat. Fortunately my test suite caught this one, but.. heads up!

wintondeshong
  • 1,129
  • 14
  • 18