On Mon, 13 Feb 2006 eastcoastcoder / gmail.com wrote:

> Very often I have a question method, which, in some cases, the caller
> would want to know why as well.
>
> Examples:
>
> def valid?
> end
>
> def abort?
> end
>
> Ruby does not allow subclassing true and false, so, if these methods
> return one of those, they can't return any additional info.  But
> sometimes the caller needs additional info, as in:
>
> if !valid? logger.warn "Not valid: #{why not?}"
>
> What is the best way to handle this?  I could have those methods set
> @instance_variables, but this seems a little hackish, and could
> introduce race conditions.
>
> Is there anyway to return false, "reason", or something of that sort?
> What is the preferred, idiomatic way of doing this?

use a block to return info:

     harp:~ > cat a.rb
     class C
       def initialize(x) @x = x end
       def valid?()
         if @x == 42
           true
         else
           yield "x is not 42" rescue nil
           false
         end
       end
     end

     c = C::new 43
     unless c.valid?{|reason| warn "not valid : #{ reason }" }
       # do something
     end

     c = C::new 42
     c.valid?{|reason| warn "not valid : #{ reason }" }


     harp:~ > ruby a.rb
     not valid : x is not 42



or invert your logic so info can be added:

   harp:~ > cat a.rb
   class C
     def initialize(x) @x = x end
     def invalid?() @x == 42 ? false : "x is not 42" end
   end

   c = C::new 43
   if((reason = c.invalid?))
     puts reason
   end

   c = C::new 42
   if((reason = c.invalid?))
     puts reason
   end


   harp:~ > ruby a.rb
   x is not 42


hth.

-a

-- 
happiness is not something ready-made.  it comes from your own actions.
- h.h. the 14th dali lama