[ruby] Why are exclamation marks used in Ruby methods?

In Ruby some methods have a question mark (?) that ask a question like include? that ask if the object in question is included, this then returns a true/false.

But why do some methods have exclamation marks (!) where others don't?

What does it mean?

This question is related to ruby methods naming-conventions immutability

The answer is


!

I like to think of this as an explosive change that destroys all that has gone before it. Bang or exclamation mark means that you are making a permanent saved change in your code.

If you use for example Ruby's method for global substitutiongsub!the substitution you make is permanent.

Another way you can imagine it, is opening a text file and doing find and replace, followed by saving. ! does the same in your code.

Another useful reminder if you come from the bash world is sed -i has this similar effect of making permanent saved change.


Bottom line: ! methods just change the value of the object they are called upon, whereas a method without ! returns a manipulated value without writing over the object the method was called upon.

Only use ! if you do not plan on needing the original value stored at the variable you called the method on.

I prefer to do something like:

foo = "word"
bar = foo.capitalize
puts bar

OR

foo = "word"
puts foo.capitalize

Instead of

foo = "word"
foo.capitalize!
puts foo

Just in case I would like to access the original value again.


It is most accurate to say that methods with a Bang! are the more dangerous or surprising version. There are many methods that mutate without a Bang such as .destroy and in general methods only have bangs where a safer alternative exists in the core lib.

For instance, on Array we have .compact and .compact!, both methods mutate the array, but .compact! returns nil instead of self if there are no nil's in the array, which is more surprising than just returning self.

The only non-mutating method I've found with a bang is Kernel's .exit! which is more surprising than .exit because you cannot catch SystemExit while the process is closing.

Rails and ActiveRecord continues this trend in that it uses bang for more 'surprising' effects like .create! which raises errors on failure.


! typically means that the method acts upon the object instead of returning a result. From the book Programming Ruby:

Methods that are "dangerous," or modify the receiver, might be named with a trailing "!".


From themomorohoax.com:

A bang can used in the below ways, in order of my personal preference.

1) An active record method raises an error if the method does not do what it says it will.

2) An active record method saves the record or a method saves an object (e.g. strip!)

3) A method does something “extra”, like posts to someplace, or does some action.

The point is: only use a bang when you’ve really thought about whether it’s necessary, to save other developers the annoyance of having to check why you are using a bang.

The bang provides two cues to other developers.

1) that it’s not necessary to save the object after calling the method.

2) when you call the method, the db is going to be changed.

http://www.themomorohoax.com/2009/02/11/when-to-use-a-bang-exclamation-point-after-rails-methods


Simple explanation:

foo = "BEST DAY EVER" #assign a string to variable foo.

=> foo.downcase #call method downcase, this is without any exclamation.

"best day ever"  #returns the result in downcase, but no change in value of foo.

=> foo #call the variable foo now.

"BEST DAY EVER" #variable is unchanged.

=> foo.downcase! #call destructive version.

=> foo #call the variable foo now.

"best day ever" #variable has been mutated in place.

But if you ever called a method downcase! in the explanation above, foo would change to downcase permanently. downcase! would not return a new string object but replace the string in place, totally changing the foo to downcase. I suggest you don't use downcase! unless it is totally necessary.


The exclamation point means many things, and sometimes you can't tell a lot from it other than "this is dangerous, be careful".

As others have said, in standard methods it's often used to indicate a method that causes an object to mutate itself, but not always. Note that many standard methods change their receiver and don't have an exclamation point (pop, shift, clear), and some methods with exclamation points don't change their receiver (exit!). See this article for example.

Other libraries may use it differently. In Rails an exclamation point often means that the method will throw an exception on failure rather than failing silently.

It's a naming convention but many people use it in subtly different ways. In your own code a good rule of thumbs is to use it whenever a method is doing something "dangerous", especially when two methods with the same name exist and one of them is more "dangerous" than the other. "Dangerous" can mean nearly anything though.


This naming convention is lifted from Scheme.

1.3.5 Naming conventions

By convention, the names of procedures that always return a boolean value usually end in ``?''. Such procedures are called predicates.

By convention, the names of procedures that store values into previously allocated locations (see section 3.4) usually end in ``!''. Such procedures are called mutation procedures. By convention, the value returned by a mutation procedure is unspecified.


Called "Destructive Methods" They tend to change the original copy of the object you are referring to.

numbers=[1,0,10,5,8]
numbers.collect{|n| puts n*2} # would multiply each number by two
numbers #returns the same original copy
numbers.collect!{|n| puts n*2} # would multiply each number by two and destructs the original copy from the array
numbers   # returns [nil,nil,nil,nil,nil]

Examples related to ruby

Uninitialized Constant MessagesController Embed ruby within URL : Middleman Blog Titlecase all entries into a form_for text field Ruby - ignore "exit" in code Empty brackets '[]' appearing when using .where find_spec_for_exe': can't find gem bundler (>= 0.a) (Gem::GemNotFoundException) How to update Ruby Version 2.0.0 to the latest version in Mac OSX Yosemite? How to fix "Your Ruby version is 2.3.0, but your Gemfile specified 2.2.5" while server starting Is the server running on host "localhost" (::1) and accepting TCP/IP connections on port 5432? How to update Ruby with Homebrew?

Examples related to methods

String method cannot be found in a main class method Calling another method java GUI ReactJS - Call One Component Method From Another Component multiple conditions for JavaScript .includes() method java, get set methods includes() not working in all browsers Python safe method to get value of nested dictionary Calling one method from another within same class in Python TypeError: method() takes 1 positional argument but 2 were given Android ListView with onClick items

Examples related to naming-conventions

How to name Dockerfiles What is the difference between .yaml and .yml extension? Is there a naming convention for git repositories? What's the name for hyphen-separated case? Should I use "camel case" or underscores in python? Is there a naming convention for MySQL? What is the javascript filename naming convention? REST URI convention - Singular or plural name of resource while creating it What is the standard naming convention for html/css ids and classes? What are naming conventions for MongoDB?

Examples related to immutability

Enums in Javascript with ES6 Correct way to push into state array What is difference between mutable and immutable String in java Const in JavaScript: when to use it and is it necessary? Aren't Python strings immutable? Then why does a + " " + b work? String is immutable. What exactly is the meaning? Immutable vs Mutable types Java Immutable Collections Set System.Drawing.Color values Remove specific characters from a string in Python