Return values in Ruby, where are they?
It really bothers me that code can become unclear or obscure by not communicating very simple facts, like what a method is returning. A good practice used in Java is to return a 'results', meaning one keeps the return value of a method stored in a variable named 'results'. It can be a String, Boolean, or whatever.
Ruby is one of my favorite languages right now, but handles return values for methods very differently than languages like Java. Ruby does not require an explicit 'return' statement, but can return the last executed statement results by default. This can be confusing.
Discovering what this return value might be can be more time consuming that is necessary and is immediately taken care of by simply supplying a 'return' statement. Cost is nothing, results are clarity. I provide an example from my current running project, AbTLinux:
## # Cleans up this packages source build directory. # # RETURNS: boolean - True if the completes successfully, # otherwise false. ## def remove_build puts "Removings build..." if ($REMOVE_BUILD_SOURCES) buildSourcesLocation = "#{$BUILD_LOCATION}/#{srcDir}" if (!File.directory?(buildSourcesLocation)) return true end if (!FileUtils.rm_rf buildSourcesLocation, :verbose => true ) return false end end return true end
Hi Eric,
ReplyDeletethanks for the kinds words about On Ruby, and for the contest submission. Good luck!
Hi Pate,
ReplyDeleteAny time, keep putting up the interesting Ruby content. There are not as many good sites that are active on this front as one would imagine.
I suppose it's partly a matter of taste, but I have to disagree with you. Explicit returns are too much like gotos and make it harder to follow the control flow. I much prefer a functional style, which is quite natural in Ruby.
ReplyDeleteAlso, this code reads like Java code, not Ruby code. And I find it ironic that the code sample you use has so many examples of poor Ruby practices and non-Ruby style. Camel-case variables, comments with typos and missing words, unnecessary parens for conditionals, missing parens for method calls, using string interpolation instead of File.join to construct a path, and using global variables. I don't know if this is your own code or someone else's, but it's not a great choice to show good style or practices.
I'd write the method as so:
def remove_build
puts "Removing build..."
if $REMOVE_BUILD_SOURCES
sources_path = File.join($BUILD_LOCATION, src_dir)
File.directory?(sources_path) && FileUtils.rm_rf(sources_path, :verbose => true)
else
true
end
end
Josh,
ReplyDeleteThanks for the input, constructive comments always welcome!
You are right on most of this, I have chosen a piece of code I wrote in the very beginning of my Ruby experience. Most of this project has been refactored, but this one has not yet made it. Furthermore, my day job is indeed Java, so the transition to Ruby indeed looked a bit Java-ish. The point was only to illustrate the explicit return statements.
The camel-cased variables should be removed, the parens are a style choice (I like more than less for clarity, but his is another best-practice story), and global variables are part of the design choice. The File.join tip is a good one and I will be applying that one for sure.
I understand that a functional programmer would prefer less (as your method shows). It is indeed a matter of choice/style.