Ruby DISCUSSION

Ruby methods ending in !: why does upcase! sometimes return nil and break my method chain?

Started by vannhan Ruby bang methodsin-place mutationnil return valuemethod chainingfrozen strings
4 replies 248 views 5 participants
Latest activity · 30 Sep 2026

Ruby methods ending in !: why does upcase! sometimes return nil and break my method chain?

vannhan Ruby Forum
#1

I clean up incoming command strings with cmd = line.strip!.downcase!. It works for most input, but for some lines I get NoMethodError: undefined method 'downcase!' for nil, and for others cmd ends up nil even though line looks fine. Replacing the bang methods with strip.downcase fixes it.

What does the exclamation mark mean on a Ruby method, why do these methods return nil, and when is it right to use them?

Community replies 4

Re: Ruby methods ending in !: why does upcase! sometimes return nil and break my method chain?

#2

The ! is simply part of the method name. By convention it marks the more dangerous of a pair: upcase returns a new string and leaves the receiver alone, upcase! modifies the receiver in place. In the core classes "dangerous" nearly always means "mutates the receiver".

Many of these in-place methods on String return nil when they made no change. "abc".downcase! is nil because the string was already lower case; "ABC".downcase! returns the modified string. The same goes for strip!, chomp!, squeeze!, gsub! and sub!.

Re: Ruby methods ending in !: why does upcase! sometimes return nil and break my method chain?

#3

So your chain fails in two ways. If line has no surrounding whitespace, strip! returns nil and the next call is made on nil: that is the NoMethodError. If there was whitespace but the text was already lower case, downcase! returns nil and that nil is assigned to cmd.

The return value of a bang method is a change indicator, not a result to build on. Either chain the non-bang versions, cmd = line.strip.downcase, or call the bang versions as separate statements and keep using line: line.strip! then line.downcase!.

Re: Ruby methods ending in !: why does upcase! sometimes return nil and break my method chain?

#4

Two things the convention does not tell you. First, plenty of mutating methods have no bang: <<, push, concat, clear, replace and insert all modify the receiver. The mark is only used where a non-mutating twin exists. Second, the nil behaviour is not uniform: Array#uniq! and compact! return nil when nothing changed, while sort! and map! always return the array. Check the documentation of the specific method before relying on its return value.

Outside the core library the mark can mean something else entirely; in Rails, save! raises an exception on failure where save returns false.

Re: Ruby methods ending in !: why does upcase! sometimes return nil and break my method chain?

#5

In-place mutation also affects everyone who holds the same object. After a = "on" and b = a, calling b.upcase! changes what a sees, because both variables refer to one string. A method that runs strip! on its argument is altering the caller's data. Copy first with dup if you need a private version.

When a file starts with the magic comment # frozen_string_literal: true, string literals are frozen, and a bang method on one raises FrozenError. The case for bang methods is large buffers, where avoiding a second copy of a multi-megabyte string is worth it; for short command strings the non-bang forms are safer and the difference in speed does not matter.

TEP COMMUNITY