2

I'm trying to learn Ruby by reading code, but I bumped into the following situation, which I cannot find in any of my tutorials/cheatsheets.

def foo!
    # do bar

    return bar  
  end

What is the point of "!" in a method definition?

Jon Cairns
  • 11,247
  • 3
  • 37
  • 65
Bogdan M.
  • 2,033
  • 6
  • 29
  • 48

3 Answers3

11

Ruby doesn't treat the ! as a special character at the end of a method name. By convention, methods ending in ! have some sort of side-effect or other issue that the method author is trying to draw attention to. Examples are methods that do in-place changes, or might throw an exception, or proceed with an action despite warnings.

For example, here's how String#upcase! compares to String#upcase:

1.9.3p392 :004 > foo = "whatever"
 => "whatever"
1.9.3p392 :005 > foo.upcase
 => "WHATEVER"
1.9.3p392 :006 > foo
 => "whatever"
1.9.3p392 :007 > foo.upcase!
 => "WHATEVER"
1.9.3p392 :008 > foo
 => "WHATEVER"

ActiveRecord makes extensive use of bang-methods for things like save!, which raises an exception on failure (vs save, which returns true/false but doesn't raise an exception).

It's a "heads up!" flag, but there's nothing that enforces this. You could end all your methods in !, if you wanted to confuse and/or scare people.

Jim Stewart
  • 15,555
  • 4
  • 60
  • 83
  • May want to add a note that `!` methods tend to have different return values (most notably `nil` when nothing changed) which can cause unexpected and subtle bugs. – Aaron K Apr 30 '13 at 14:29
1

! is a "bang" method, which changes the receiver and is a convention in Ruby.

You can define a ! version which might work like a non-bang method, but then it would then mislead other programmers if they didn't look at your method definition.

bang method in turn returns nil when no changes made to the receiver.

Examples without ! - You can see that the source string has not been changed:

str = "hello"
p str.delete("l") #=> "heo"
p str #=> "hello"

Examples with ! - You can see that the source string has been changed:

str = "hello"
p str.delete!("l") #=> "heo"
p str #=> "heo"

NOTE: There are some non-bang version methods, which also can change the receiver object:

str = "hello"
p str.concat(" world") #=> "hello world"
p str #=> "hello world"
Arup Rakshit
  • 109,389
  • 25
  • 234
  • 293
  • Thank you, it makes sense, so it is just a ruby convention :D – Bogdan M. Apr 30 '13 at 14:03
  • The bang isn't used by itself. It's used when there is an non-bang alternative. http://dablog.rubypal.com/2007/8/15/bang-methods-or-danger-will-rubyist – thomthom Apr 30 '13 at 14:19
  • @thomthom I know that, did I mention anything wrong there? point me to there,I will correct. – Arup Rakshit Apr 30 '13 at 14:21
  • This answer is misleading. The `!` indicates that the method is a potentially dangerous version of another method. Many times, `!` does modify the receiver (and that is what is dangerous), but other times other effects occur. For example, in Rails, the ActiveRecord `save` and `save!` both modify the receiver (in a sense) but the `save!` method potentially raises and exception. Jim Stewart's answer is the correct answer. –  Apr 30 '13 at 16:05
  • @LeviStanley I don't know in what sense you told my answer is misleading. but wanted to tell you bang method returns `nil` if changes are not possible.This question is tagged as `Ruby`. So according to ruby what I wrote bang method does exactly like that. – Arup Rakshit Apr 30 '13 at 16:14
0

! is not a method definition but is an convention used when you declaring an method and this method will change the object.

1.9.3-p194 :004 > a="hello "
 => "hello " 
1.9.3-p194 :005 > a.strip
 => "hello" 
1.9.3-p194 :006 > a
 => "hello " 
1.9.3-p194 :007 > a.strip!
 => "hello" 
1.9.3-p194 :008 > a
 => "hello" 
pierrotlefou
  • 36,417
  • 33
  • 130
  • 168