upcase!(to get the all-uppercase version of a string) and
uniq!(to get the unique elements of an array). Long story short, the bang means that you should use it with caution.
Usually this is because it modifies the object passed and returns it, as opposed to returning a modified copy of it. (In Ruby on Rails and many similar frameworks, this may also be because it will throw an exception if anything goes wrong. However, we will focus on core Ruby methods.) I'll show you another reason in a moment, but for now, let's just examine the normal usually-expected behavior. For instance:
will output FOO and then foo. While
str = 'foo' p str.upcase p str
upcasereturned the uppercased version of
str, it did not modify
str. On the other claw, if we add a bang, doing:
we get FOO and then FOO again! In other words,
str = 'foo' p str.upcase! p str
upcase!returned the uppercased version, just as the non-bang version did, but it also uppercased
Similarly, if we use
we get [1, 3, 7] and then [1, 3, 3, 7], showing again that the non-bang version returned the unique values within
arr = [1, 3, 3, 7] p arr.uniq p arr
arr, but did not modify
arr, whereas if we add a bang and do:
we get [1, 3, 7] and then [1, 3, 7] again, showing that
arr = [1, 3, 3, 7] p arr.uniq! p arr
arritself was modified this time.
So far so good.
But wait! There's more! There's another big bad gotcha waiting to getcha!
Do not depend on the bang versions returning the same value as the non-bang versions! (Even though that value seems to be the whole point of both functions!)
In the specific cases above, yes they do. But let's look at what happens if the variable is already how we want -- in other words, if the string is already all uppercase, or the array already has only unique values. If we do:
then, as expected, since it already fit our needs,
str = 'FOO' p str.upcase! p str
stris unchanged. But look at
Let's see what happens in the numeric case. If we do:
then, just as above,
arr = [1, 3, 7] p arr.uniq! p arr
arris unchanged... but
nil! How come?
Long story short, standard Ruby bang methods often return
nilif no change was needed.
Worse yet, even that is not completely consistent. When using any bang-method that you are not already very familiar with, be sure to RTFM.