I recently came across this issue in some code I was developing.
Going thru the archives I saw that there was a discussion of this sometime
ago but I wasn't sure if a consensus had been reached.
Should the return value of mutating methods (syntactically indicated with a
suffix 'bang') be specified? Should they return value be nil or the object
being modified?
For example, suppose you want to read in a line, remove a terminating
newline and downcase it. Couple of choices are:
line = line.chomp.downcase # creates unnecessary garbage
vs
line.chomp! ; line.downcase! # verbose, seems in-elegant
There is an expression elegance if we were able to say:
line.chomp!.downcase!
In order to be able to chain mutating method calls (and the resulting
conciseness of expression) I would vote for all builtin mutating methods to
return the object so changed. A similar convention being used for all user
written mutating methods.
*
I'm not sure if there is a "right" or "wrong" answer to this question of
(nil vs modified object return value). Some other language communities have
dicussed long and hard on this issue ...
The Scheme community have -long- discussed this and have moved in favor of
leaving the return value of side-effecting routines to be "undefined".
Different implementations, depending on the context return different values,
e.g.,
(define a 3) ;-> 'a'
(set! a 3) ;-> 3
etc
while others (Chez Scheme) have explicitly created an "undefined" object
(#<void>).
In OOSC Meyer points out the benefits of conceptually separating two types of
methods "queries" (no side-effect) from "commands (side-effects). But his
argument is more in the context of testing for pre/post conditions and
invariants --- one can't test using a query that also changes its argument.
A sort of CS equivalent of "Heisenberg uncertainty" :-). The prototypical
example being the problem of testing a stack with an implementation of #pop
which returns the top value -and- removes it. He prefers #top (query) and
#pop (command which just removes the top element without returning a value).
Ruby (like Scheme) has the very nice ability to -syntactically-
differentiate between queries and commands. So it seems that for the
Stack#pop objection, if one provides #top and #pop! (return + mutate) and
uses the convention that no "bang" methods should be used in
pre/post/invariant testing things should be OK.
Raja