Why are exclamation marks used in Ruby methods?
Asked Answered
T

13

663

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?

Theophylline answered 4/3, 2009 at 20:2 Comment(3)
synonym: bang, exclamation markBerga
The accepted answer should be changed to https://mcmap.net/q/63754/-why-are-exclamation-marks-used-in-ruby-methods. See wobblini.net/bang.txt and ruby-forum.com/topic/176830#773946 -- "The bang sign means "the bang version is more dangerous than its non bang counterpart; handle with care"" -MatzBoorman
The bang method would be a great design choice if only and all bang methods were dangerous. Sadly they are not, and so it becomes a frustrating exercise in memorising what is and isn't mutable.Laszlo
R
749

In general, methods that end in ! indicate that the method will modify the object it's called on. Ruby calls these as "dangerous methods" because they change state that someone else might have a reference to. Here's a simple example for strings:

foo = "A STRING"  # a string called foo
foo.downcase!     # modifies foo itself
puts foo          # prints modified foo

This will output:

a string

In the standard libraries, there are a lot of places you'll see pairs of similarly named methods, one with the ! and one without. The ones without are called "safe methods", and they return a copy of the original with changes applied to the copy, with the callee unchanged. Here's the same example without the !:

foo = "A STRING"    # a string called foo
bar = foo.downcase  # doesn't modify foo; returns a modified string
puts foo            # prints unchanged foo
puts bar            # prints newly created bar

This outputs:

A STRING
a string

Keep in mind this is just a convention, but a lot of Ruby classes follow it. It also helps you keep track of what's getting modified in your code.

Recurved answered 4/3, 2009 at 20:4 Comment(8)
There's also cases like exit versus exit! and (in rails) save versus save!Enterogastrone
Be very careful - many smaller libraries don't follow this convention. If strange things are happening, often replacing obj.whatever! with obj=obj.whatever! fixes it. Very frustrating.Hydrocellulose
bang is also used for methods that raise an exception when the method without does not, e.g.: save and save! in ActiveRecordBethought
What Save! actually does in Rails?Decarbonate
@AbhilashAK save! raises an error if it cannot save. This is opposed to regular save returning true/false.Peppard
@tgamblin There are lots of methods in Ruby that mutate without bangs. There are even rare methods that do not mutate WITH a bang but do something surprising like raise errors or skip errors. Bangs are used to say this is the more unusual version of the method and I think this should be reflected in your answer since it is marked as correct.Peppard
@Bethought I arrived here after learning of that use of ! from here. How can we read more about that use? (and it seems odd to use the same character for two totally different things? - I wonder why that design choice was made)Jasmin
ActiveRecord is a good example of cryptic behaviour (mutability), you need to call valid? (save does it) to have the errors filled. The bang is also used for "dangerous" methods throwing exceptions like save!. It's a loose convention we can't rely too much on it. I suggest you're clear with the team what you mean the ! for all projects.Bethought
A
181

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.

Appleby answered 4/3, 2009 at 21:59 Comment(0)
P
93

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.

Panache answered 4/3, 2009 at 21:44 Comment(1)
+1 to this answer since has a documentation that give reasonable explanations for the ! usage. Really good answer StevenMamey
S
28

! 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 "!".

Shafer answered 4/3, 2009 at 20:4 Comment(0)
P
27

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.

Peppard answered 15/2, 2014 at 22:38 Comment(0)
U
20

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.

Untuck answered 9/9, 2011 at 0:5 Comment(0)
P
6

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.

Postgraduate answered 14/9, 2013 at 11:51 Comment(0)
M
5
!

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.

Mccallum answered 3/4, 2017 at 15:16 Comment(0)
D
2

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.

Dashboard answered 23/7, 2015 at 21:10 Comment(7)
Because your answer was not helpful in any way. "Bottom line: ! methods just change the value of the object they are called upon" is just not true.Hettie
@Hettie it does change the value of the object. ! mutates the object rather than returning a modified copy.Dashboard
So what do you think this does? User.create!Hettie
@Hettie in what context? ActiveRecord?Dashboard
Yes, ActiveRecord.Hettie
Heres a better argument for why your answers is plain wrong. Read Matz comment on bang "!". ruby-forum.com/topic/176830#773946. Do you still feel that your "Bottom line: ! methods just change the value of the object they are called upon" is true in any way what so ever?Hettie
@Darwin: Completely true? No, and I see that now. "In any way whatsoever?" Yes. Modifying its argument, or the object upon which a ! method is called, is obviously "dangerous" -- that goes without saying; any method that mutates any of its arguments is dangerous because you could lose data. I'll admit: I was taught that ! modifies its object and I never really questioned that. So I thank you for this.Dashboard
N
1

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]
Nuristan answered 23/5, 2017 at 14:43 Comment(0)
S
1

My answer explains the significance of Ruby methods with exclamation marks/shebangs in the context of Ruby on Rails (RoR) model validations.

Essentially, whenever developers define Model validations (explained here), their ultimate goal is to decline a database record change & raise/throw the relevant exception(s) in case invalid data has been submitted to update the record in question.

RoR ActiveRecord gem defines various model manipulation methods (Ruby on Rails guides.). Among the methods, the valid? method is the only one that triggers validation without database action/modification. The rest of the methods attempt to change the database.

These methods trigger callbacks whenever they run. Some of the methods in the list feature a sister method with a shebang. What is the difference between the two? It has to do with the form of callback returned whenever a record validation fails.

Methods without the exclamation/shebang merely return a boolean false in the event of record validation failure while the methods with a shebang raise/throw an exception which can then be handled appropriately in code.

Slice answered 27/11, 2022 at 15:4 Comment(0)
C
0

Just as a heads-up, since I experienced this myself.

In Ruby, ! mutates the object and returns it. Otherwise it will return nil.

So, if you are doing some kind of operations on an array for example, and call the method .compact! and there is nothig to compact, it will return nil.

Example:

arr = [1, 2, 3, nil]
arr.compact!
=> [1, 2, 3]

Run again arr.compact!
=> nil

It is better to explicitly return again the array arr if you need to use it down the line, otherwise you will get the nil value.

Example:

arr = [1, 2, 3]
arr.compact! => nil
arr # to get the value of the array
Cholinesterase answered 6/2, 2023 at 10:20 Comment(0)
S
0

0

exclamation marks ("!") at the end of method names are a naming convention. They indicate that the method can be more dangerous, performs a destructive action, or can modify the object it's called on. It's a way to alert developers about the special behaviour of the method. The exclamation mark doesn't have a specific meaning in the Ruby language itself but is widely used in the community to imply potential side effects or modifications of the object.

Example: def sort!(array) array.sort! end

numbers = [3, 1, 2] sort!(numbers) puts numbers.inspect # Output: [1, 2, 3]

the sort! method sorts the array in place and modifies the original numbers array. The exclamation mark indicates that this method changes the object it operates on.

Siusan answered 3/10, 2023 at 7:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.