[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Idiomatic ruby

eastcoastcoder

2/12/2006 11:22:00 PM

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?

5 Answers

Gavin Kistner

2/12/2006 11:59:00 PM

0

How about returning multiple values?

def valid?
[ @is_valid_flag, @error_message ]
end

Alex Fenton

2/13/2006 12:17:00 AM

0

eastcoastcoder@gmail.com wrote:

> 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?}"

Use exceptions, which can contain readable messages

def my_meth
validate
# .. proceed
rescue => err
logger.warn "Not valid #{err}"
end

# if you want a boolean-style method
def valid?
validate && true # assuming validate returns some kind of true value
rescue
false
end

alex

David Vallner

2/13/2006 12:33:00 AM

0

Dna Pondelok 13 Február 2006 01:03 Phrogz napísal:
> How about returning multiple values?
>
> def valid?
> [ @is_valid_flag, @error_message ]
> end

Wouldn't ever evaluate as false, which means all the predicates would have to
be true on a failure, which might be a bit confusing - I prefer to code
assertively if possible.

David Vallner


Brian Buckley

2/13/2006 4:04:00 PM

0

>
> 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.
>

I'm not sure I'd agree that it is hackish to set @instance_variables (or
perhaps to use a setter instead) to capture learned info. A naming
convention might help (maybe remove the "?' and add "_reason")

class Foo
attr_accessor :valid_reason
def valid?
...
self.valid_reason = "age is too young"
false
end
end

Robert Klemme

2/13/2006 4:19:00 PM

0

Brian Buckley wrote:
>> 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.
>>
>
> I'm not sure I'd agree that it is hackish to set @instance_variables
> (or perhaps to use a setter instead) to capture learned info. A
> naming convention might help (maybe remove the "?' and add "_reason")
>
> class Foo
> attr_accessor :valid_reason
> def valid?
> ...
> self.valid_reason = "age is too young"
> false
> end
> end

IMHO it's bad practice to store this info in the instance. It really
doesn't belong there; you run into all sorts of problems (race conditions
in concurrent apps, consistence - you need to clear this when the instance
state changes...).

The best solution seems to be to use an exception.

class Foo
attr_accessor :name

def ensure_valid
self.name or raise "Empty name."
end
end

begin
f=Foo.new
f.ensure_valid
f.do_stuff()
rescue RuntimeError => e
$stderr.puts "Invalid because of: #{e.message}"
end

Kind regards

robert