Montag, 6. Mai 2013

Boolean method parameter assignment in Ruby

At first: prevent using boolean parameters in method definitions.
But let's assume you have to call a method that expects a boolean parameter like:
class Human
  def go backward=false
    puts "#{self.class} is going " + 
      (backward ? "backward" : "forward")
  end
end
A human can go forward and backward.
We want a human to go backward. If you would code it this way:
human = Human.new
# human goes backward
human.go true
please go on reading, because there is something to improve. At first the output is as expected:
Human is going backward
The code works but you have to agree, that "human.go true" is not readable (that's why there is a line of documentation). But we can improve the readability:
human = Human.new
human.go :backward
also results in:
Human is going backward
In Ruby a Symbol and all objects except instances of Nil and False class are true. Besides using an expressive Symbol can save the line of documentation, because the code documents itself. Awesome! Going forward could be default or explicit:
human = Human.new
human.go # default forward
human.go not(:backward) # explicit
The "not" before the Symbol inverts the assigned parameter. You also could use a bang ("human.go !:backward"). The result:
Human is going forward
Human is going forward
Though I'd prefer having a well designed API method ;-)

Supported by Ruby 1.9.3

Kommentare:

  1. not(:backward) is a bit awkward. Instead I would suggest:

    class Human
    DIRECTIONS = [ :forward, :backward ]
    def go (direction = :forward)
    # in the real world, one could also convert strings to
    # symbols, and construct instructions from valid-value list.
    raise "Invalid direction; must use :forward or :backward." unless DIRECTIONS.include?(direction)
    puts "is going #{direction}"
    end
    end

    (Forgive the lack of indentation; I put it in, but the preview shows it being stripped out.)

    That code still seems a bit clumsy to me, though; maybe there's a better way, without all the overhead of declaring a new class specifically to hold directions or something like that. (In C, I would just make it an enum type.)

    AntwortenLöschen
  2. Hi Dave,
    it looks like I didn't make clear enough the intention of the post. The post was not intended to design a method without having a boolean parameter. At the beginning I also pointed out that a boolean parameter should be avoided. The post was about how to deal with an already existing method (say an API receiver like RubyOnRails or others) having a boolean parameter in a clean way.
    If you suggest a cleaner way, how to deal with boolean parameters, please let me know.

    AntwortenLöschen