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