Type checking function parameters

More or less all my functions look something like

def foo bar baz quux
   if not bar.is_a? String or
      not baz.is_a? FunkyDinosaur or
      not quux.respond_to? "getEatenByFunkyDinosaur"
      #complain about errors w/ raise or app specific complain function
   end
   # do some stuff
end

There has got to be a better way to go about this parameter checking
business, but googling is not working (bad search terms maybe). Is
there?

And I don't really mean other ways of writing the same logic, i.e.

3 statements that look like:

complain "baz is no dinosaur!" unless baz.is_a? FunkyDinosaur

does not seem a whole lot better to me than the above example

···

--
Posted via http://www.ruby-forum.com/.

You're looking at the problem inside-out which is why you're finding yourself in such a tangle: in Ruby explicit type checking is very rare and in cases where you think you need it you're generally wrong and fighting against the language rather than flowing with it. Google the term "Duck Typing" and you should find lots of helpful advice on how to write your code in an idiomatic manner whilst still covering your arse against the kind of type errors which can occur using Exception handling.

Ellie

Eleanor McHugh
Games With Brains
http://slides.games-with-brains.net

···

On 3 Sep 2009, at 05:04, Nick Green wrote:

More or less all my functions look something like

def foo bar baz quux
  if not bar.is_a? String or
     not baz.is_a? FunkyDinosaur or
     not quux.respond_to? "getEatenByFunkyDinosaur"
     #complain about errors w/ raise or app specific complain function
  end
  # do some stuff
end

There has got to be a better way to go about this parameter checking
business, but googling is not working (bad search terms maybe). Is
there?

And I don't really mean other ways of writing the same logic, i.e.

3 statements that look like:

complain "baz is no dinosaur!" unless baz.is_a? FunkyDinosaur

does not seem a whole lot better to me than the above example

----
raise ArgumentError unless @reality.responds_to? :reason

My first stab at some Ruby started like this too.

Let it go.

Stop caring about what type your parameters are, and just let them
complain if you try to call a method which they don't respond to.

It's unsatisfying at first, if you've been brainwashed into writing
code where you check everything to try to prevent illegal instructions
from happening, but you'll soon realise that it actually gives you a
lot of freedom and power.

If it walks like a duck and quacks like a duck then it's probably a duck.

···

On Thu, Sep 3, 2009 at 9:49 AM, Eleanor McHugh<eleanor@games-with-brains.com> wrote:

On 3 Sep 2009, at 05:04, Nick Green wrote:

More or less all my functions look something like

def foo bar baz quux
if not bar.is_a? String or
not baz.is_a? FunkyDinosaur or
not quux.respond_to? "getEatenByFunkyDinosaur"
#complain about errors w/ raise or app specific complain function
end
# do some stuff
end

There has got to be a better way to go about this parameter checking
business, but googling is not working (bad search terms maybe). Is
there?

And I don't really mean other ways of writing the same logic, i.e.

3 statements that look like:

complain "baz is no dinosaur!" unless baz.is_a? FunkyDinosaur

does not seem a whole lot better to me than the above example

You're looking at the problem inside-out which is why you're finding
yourself in such a tangle: in Ruby explicit type checking is very rare and
in cases where you think you need it you're generally wrong and fighting
against the language rather than flowing with it. Google the term "Duck
Typing" and you should find lots of helpful advice on how to write your code
in an idiomatic manner whilst still covering your arse against the kind of
type errors which can occur using Exception handling.

Ellie

Eleanor McHugh
Games With Brains
http://slides.games-with-brains.net
----
raise ArgumentError unless @reality.responds_to? :reason

--
Paul Smith
http://www.nomadicfun.co.uk

paul@pollyandpaul.co.uk

OK...

I see the idea, and it is tempting. For code written for me to be used
by me it is in fact ideal. However, I guess I have two follow up
questions, both about failing gracefully:

What is the "right" way to make sure the errors these functions report
are nice to people who may use the functions/libraries I code? "Foo.bar
takes a Duck, not a Cow" would be a very helpful error message. object
of type Cow does not have method of type quack, is also not a bad error
message, but it would be nice to let the user know which type of object
in fact does have the method "quack" (presumably it would not always be
as obvious as "quack"==>"duck"). Or is the ruby way, since its an
interpereted language, for a user of my library to crack open the ruby
or rdoc/ri and look?

What is the "right" way to make sure that, if my libraries or functions
are misused by someone (possibly me :p), the user of the script/program
receives a non-programmer-targeted friendly error message like "Whoops,
we sent a Cow to do a Ducks job. Feel free to report the bug to
cows.and.ducks.sorting.co@notarealemail.com. Make sure to include the
following: <normal error dump>"?

···

--
Posted via http://www.ruby-forum.com/.

I see the idea, and it is tempting. For code written for me to be used
by me it is in fact ideal. However, I guess I have two follow up
questions, both about failing gracefully:

What is the "right" way to make sure the errors these functions report
are nice to people who may use the functions/libraries I code? "Foo.bar
takes a Duck, not a Cow" would be a very helpful error message. object
of type Cow does not have method of type quack, is also not a bad error
message, but it would be nice to let the user know which type of object
in fact does have the method "quack" (presumably it would not always be
as obvious as "quack"==>"duck"). Or is the ruby way, since its an
interpereted language, for a user of my library to crack open the ruby
or rdoc/ri and look?

The Ruby way isn't to try and defend against behaviour which is out of your control. By publishing an API for your library you provide a contract and it is the responsibility of the programmer using your library to respect and conform to that contract. Whilst this can seem quite daunting if you come from a language such as Java, you'll find that it soon becomes a great liberator - not least because all objects that respond to a particular message can be used interchangeably.

Likewise exception handling allows you to define clean error recovery based on scope.

What is the "right" way to make sure that, if my libraries or functions
are misused by someone (possibly me :p), the user of the script/program
receives a non-programmer-targeted friendly error message like "Whoops,
we sent a Cow to do a Ducks job. Feel free to report the bug to
cows.and.ducks.sorting.co@notarealemail.com. Make sure to include the
following: <normal error dump>"?

In the general case there is no way to know the full set of objects which can respond to a given message at a given time: a duck may quack, but so for that matter might a duck hunter or a tape recorder. This holds in Ruby because the runtime behaviour of objects is mutable - methods might be added and removed at any time during program execution. This is why it's much more useful to rescue runtime exceptions and handle them elegantly than to worry about the class of an object.

So just relax and let duck typing happen, you'll find those tight controls your brain's learned with other languages really are irrelevant in Ruby.

Ellie

Eleanor McHugh
Games With Brains
http://slides.games-with-brains.net

···

On 3 Sep 2009, at 23:47, Nick Green wrote:
----
raise ArgumentError unless @reality.responds_to? :reason

That was so beautiful I almost teared up. :wink:

James Edward Gray II

···

On Sep 3, 2009, at 7:30 PM, Eleanor McHugh wrote:

On 3 Sep 2009, at 23:47, Nick Green wrote:

I see the idea, and it is tempting. For code written for me to be used
by me it is in fact ideal. However, I guess I have two follow up
questions, both about failing gracefully:

What is the "right" way to make sure the errors these functions report
are nice to people who may use the functions/libraries I code? "Foo.bar
takes a Duck, not a Cow" would be a very helpful error message. object
of type Cow does not have method of type quack, is also not a bad error
message, but it would be nice to let the user know which type of object
in fact does have the method "quack" (presumably it would not always be
as obvious as "quack"==>"duck"). Or is the ruby way, since its an
interpereted language, for a user of my library to crack open the ruby
or rdoc/ri and look?

The Ruby way isn't to try and defend against behaviour which is out of your control. By publishing an API for your library you provide a contract and it is the responsibility of the programmer using your library to respect and conform to that contract. Whilst this can seem quite daunting if you come from a language such as Java, you'll find that it soon becomes a great liberator - not least because all objects that respond to a particular message can be used interchangeably.

Likewise exception handling allows you to define clean error recovery based on scope.

What is the "right" way to make sure that, if my libraries or functions
are misused by someone (possibly me :p), the user of the script/program
receives a non-programmer-targeted friendly error message like "Whoops,
we sent a Cow to do a Ducks job. Feel free to report the bug to
cows.and.ducks.sorting.co@notarealemail.com. Make sure to include the
following: <normal error dump>"?

In the general case there is no way to know the full set of objects which can respond to a given message at a given time: a duck may quack, but so for that matter might a duck hunter or a tape recorder. This holds in Ruby because the runtime behaviour of objects is mutable - methods might be added and removed at any time during program execution. This is why it's much more useful to rescue runtime exceptions and handle them elegantly than to worry about the class of an object.

So just relax and let duck typing happen, you'll find those tight controls your brain's learned with other languages really are irrelevant in Ruby.

That was the home-brew beer talking - it's a particularly mellow and reflective batch :wink:

Ellie

Eleanor McHugh
Games With Brains
http://slides.games-with-brains.net

···

On 4 Sep 2009, at 03:56, James Edward Gray II wrote:

On Sep 3, 2009, at 7:30 PM, Eleanor McHugh wrote:

So just relax and let duck typing happen, you'll find those tight controls your brain's learned with other languages really are irrelevant in Ruby.

That was so beautiful I almost teared up. :wink:

----
raise ArgumentError unless @reality.responds_to? :reason

Along the lines of this thread..

I'm rough around the edges, so I'll just use some general language.

I have a habit of building my code like bunches of little black boxes.
Each box accepts a certain kind of input and returns a certain kind
of output.

For each of the boxes, I create a sort of gateway that ensures that a
box only receives its expected input, and it intelligently reports an
error if that's not the case.

Should I be loosening my grip and removing some or perhaps all of
those gateways, just like the explanations for duck typing?

···

--
http://spiralofhope.com

I would, if you provide the correct input, the gateway is not necessary (and
it provides additional steps, hence adding some small increase in execution
time). If you do not provide the correct input, it can be expected to break,
or at least work incorrectly, which should indicate that you need to check
how you are calling it. Creating a gateway that breaks it intentionally
seems redundant, and it creates more places you have to go look if you want
to change something, more code you need to manage, etc. Instead, I would
just name my variables something intuitive, and explain what variables the
code expects, in a comment.

···

On Sat, Sep 5, 2009 at 11:33 PM, spiralofhope <spiralofhope@lavabit.com>wrote:

Along the lines of this thread..

I'm rough around the edges, so I'll just use some general language.

I have a habit of building my code like bunches of little black boxes.
Each box accepts a certain kind of input and returns a certain kind
of output.

For each of the boxes, I create a sort of gateway that ensures that a
box only receives its expected input, and it intelligently reports an
error if that's not the case.

Should I be loosening my grip and removing some or perhaps all of
those gateways, just like the explanations for duck typing?

--
http://spiralofhope.com

Hi --

Along the lines of this thread..

I'm rough around the edges, so I'll just use some general language.

I have a habit of building my code like bunches of little black boxes.
Each box accepts a certain kind of input and returns a certain kind
of output.

For each of the boxes, I create a sort of gateway that ensures that a
box only receives its expected input, and it intelligently reports an
error if that's not the case.

Should I be loosening my grip and removing some or perhaps all of
those gateways, just like the explanations for duck typing?

Probably. For one thing, in Ruby, it's very, very difficult to verify
whether or not an argument is going to satify the needs of the method.
You can check whether something is of class String, for example, but
then you need to wonder why a StringIO object, or another object whose
type can handle what you want it to do, won't also work.

By "type", I do not mean "class". In Ruby, type and class are not the
same. Every object is an instance of a class, but the type of an
object is the sum of what the object is capable of at a given time.
That's a very elastic and kind of inductive thing, which is why the
notion of type is actually kind of moot in Ruby.

Of course you can get a certain amount of mileage by testing the class
of an object and assuming that if it's of a certain class, it must
behave a certain way. But by doing so, you create two problems:

   1. it doesn't really work (because class is not the same as type);
   2. you stop yourself from creating more flexible, agile (small 'a'
      :-) program design.

David

···

On Sun, 6 Sep 2009, spiralofhope wrote:

--
David A. Black / Ruby Power and Light, LLC / http://www.rubypal.com
Ruby/Rails training, mentoring, consulting, code-review
Latest book: The Well-Grounded Rubyist (http://www.manning.com/black2\)

September Ruby training in NJ has been POSTPONED. Details to follow.

Lots of helpful opinions/philosophies about ruby here.

As for the respond_to? is more useful than is_a? comment, I typecheck
almost everything with respond to (ok thats not really a "type"check...
i... check things with respond_to?)

However, heres one issue I have, its not complicated, but its simpler to
say in code than words:

def foo someint
    someint+7
end

if foo "hello"
   puts "hi"
else
   puts "oh noez!"
end

Putting this in irb only gives me an error. There are times I would
like to say, if this function works, do this, otherwise, do this. And
its not neccesarily unacceptable for the function to fail, but I wan't
to know if it failed so I can do something about that. I realize that
many (most?) functions you just figure its bad news if it fails, but I
have enough functions that I just redo/try something else/figure out
whats wrong if the function fails that I need a way to say this. In
less fun/happy languages this looks like

ret = putButterOn(my_pancake);
if (ret != BUTTER_APPLIED)
{
   buttering_queue.enqueue(my_waffle);
   return ERROR_PANCAKE_NOT_BUTTERED;
}

And here, if I don't really have my heart set on a buttered pancake,
but I need to know if this putButterOn function was not build to handle
pancakes (perhaps pancake.respond_to? "spreadButter" == false). I
realize this code is not really a likely way to handle things, but it
gets the idea across. If I don't manually check values and return
nil/false/an error code if things go wrong, how can I keep going if a
function call fails? This works for checking errors in irb, but an
actual script appears to give up when it errors...

ret = putButterOn my_pancake
if ret == nil
   butter_queue.push my_waffle
end

···

--
Posted via http://www.ruby-forum.com/.

def foo someint
   someint+7
end

begin
  foo "hello"
  puts "hi"
rescue
  puts "oh noez!"
end

Personally, I've been wondering what would happen if nil just returned nil
for every undefined method. Essentially, instead of always having to put
if x && x.value && x.value > 3

I could just put
if x.value > 3

because if x was nil, then nil.value would be nil, and nil.>(3) would be
nil.

I just wonder if this would break things, or is a naive question to ask, so
I've been a little silent about it. But it keeps coming back to me, because
a lot of edge case errors revolve around nil not responding to methods.

···

On Mon, Sep 7, 2009 at 2:12 AM, Nick Green <cruzmail.ngreen@gmail.com>wrote:

Lots of helpful opinions/philosophies about ruby here.

As for the respond_to? is more useful than is_a? comment, I typecheck
almost everything with respond to (ok thats not really a "type"check...
i... check things with respond_to?)

However, heres one issue I have, its not complicated, but its simpler to
say in code than words:

def foo someint
   someint+7
end

if foo "hello"
  puts "hi"
else
  puts "oh noez!"
end

Putting this in irb only gives me an error. There are times I would
like to say, if this function works, do this, otherwise, do this. And
its not neccesarily unacceptable for the function to fail, but I wan't
to know if it failed so I can do something about that. I realize that
many (most?) functions you just figure its bad news if it fails, but I
have enough functions that I just redo/try something else/figure out
whats wrong if the function fails that I need a way to say this. In
less fun/happy languages this looks like

ret = putButterOn(my_pancake);
if (ret != BUTTER_APPLIED)
{
  buttering_queue.enqueue(my_waffle);
  return ERROR_PANCAKE_NOT_BUTTERED;
}

And here, if I don't really have my heart set on a buttered pancake,
but I need to know if this putButterOn function was not build to handle
pancakes (perhaps pancake.respond_to? "spreadButter" == false). I
realize this code is not really a likely way to handle things, but it
gets the idea across. If I don't manually check values and return
nil/false/an error code if things go wrong, how can I keep going if a
function call fails? This works for checking errors in irb, but an
actual script appears to give up when it errors...

ret = putButterOn my_pancake
if ret == nil
  butter_queue.push my_waffle
end
--
Posted via http://www.ruby-forum.com/\.

Maybe something like this:

Hi --

Lots of helpful opinions/philosophies about ruby here.

As for the respond_to? is more useful than is_a? comment, I typecheck
almost everything with respond to (ok thats not really a "type"check...
i... check things with respond_to?)

Actually respond_to? is the closest thing to a built-in tool that Ruby
offers for type-checking. is_a? just checks class and class/module
ancestry.

However, heres one issue I have, its not complicated, but its simpler to
say in code than words:

def foo someint
   someint+7
end

if foo "hello"
  puts "hi"
else
  puts "oh noez!"
end

Putting this in irb only gives me an error. There are times I would
like to say, if this function works, do this, otherwise, do this. And
its not neccesarily unacceptable for the function to fail, but I wan't
to know if it failed so I can do something about that. I realize that
many (most?) functions you just figure its bad news if it fails, but I
have enough functions that I just redo/try something else/figure out
whats wrong if the function fails that I need a way to say this.

You'll get an exception there which you can intercept and handle. If
you're really cascading through various methods until you find one
that doesn't blow up, that's about the only way to do it. It sounds a
bit fragile, though.

David

···

On Mon, 7 Sep 2009, Nick Green wrote:

--
David A. Black / Ruby Power and Light, LLC / http://www.rubypal.com
Ruby/Rails training, mentoring, consulting, code-review
Latest book: The Well-Grounded Rubyist (http://www.manning.com/black2\)

September Ruby training in NJ has been POSTPONED. Details to follow.

Personally, I've been wondering what would happen if nil just returned nil
for every undefined method. Essentially, instead of always having to put
if x && x.value && x.value > 3

I could just put
if x.value > 3

because if x was nil, then nil.value would be nil, and nil.>(3) would be
nil.

I just wonder if this would break things, or is a naive question to ask, so
I've been a little silent about it. But it keeps coming back to me, because
a lot of edge case errors revolve around nil not responding to methods.

Can if you want:

irb(main):022:0> class NilClass
irb(main):023:1> def method_missing(*args)
irb(main):024:2> nil
irb(main):025:2> end
irb(main):026:1> end

irb(main):027:0> nil.foo.bar
=> nil
irb(main):028:0> nil > 3
=> nil

etc.

Objective-C works that way.

The downside is, for cases where you are calling a method
on an object you really did not want or expect to be nil,
you no longer get the error at the point of that method
call. To me having code fail fast in error conditions is
more important, so I don't patch NilClass as shown above.
But, ruby allows it if you really want.

Regards,

Bill

···

From: "Josh Cheek" <josh.cheek@gmail.com>

Yes... I pretty much fail at life for not seeing how I should be
handling this:

begin
rescue
end

Right on. Understood. Those go around the call TO my library IN the
calling function.

def butterUp butter_queue
  return if butter_queue.empty?
  begin
    putButterOn butter_queue.shift
  rescue err
    logMsg err
    butterUp
  end
end

Would be a good way to do it ya? Obviously this is some kind of
ruby/pseudo code hybrid, but the idea is there. Heheh I feel silly, I
forgot where one should deal with errors. Too many years of C had my
obsessed with return values and thousands of lines of error checking all
over the place.

···

--
Posted via http://www.ruby-forum.com/.

Hi --

···

On Mon, 7 Sep 2009, Bill Kelly wrote:

From: "Josh Cheek" <josh.cheek@gmail.com>

Personally, I've been wondering what would happen if nil just returned nil
for every undefined method. Essentially, instead of always having to put
if x && x.value && x.value > 3

I could just put
if x.value > 3

because if x was nil, then nil.value would be nil, and nil.>(3) would be
nil.

I just wonder if this would break things, or is a naive question to ask, so
I've been a little silent about it. But it keeps coming back to me, because
a lot of edge case errors revolve around nil not responding to methods.

Can if you want:

irb(main):022:0> class NilClass
irb(main):023:1> def method_missing(*args)
irb(main):024:2> nil
irb(main):025:2> end
irb(main):026:1> end

irb(main):027:0> nil.foo.bar
=> nil
irb(main):028:0> nil > 3
=> nil

etc.

Objective-C works that way.

The downside is, for cases where you are calling a method
on an object you really did not want or expect to be nil,
you no longer get the error at the point of that method
call. To me having code fail fast in error conditions is
more important, so I don't patch NilClass as shown above.
But, ruby allows it if you really want.

I wouldn't do it, though, even if I really wanted it :slight_smile: There may be
code in the standard library, or elsewhere, that's relying on the
documented behavior of nil.

David

--
David A. Black / Ruby Power and Light, LLC / http://www.rubypal.com
Ruby/Rails training, mentoring, consulting, code-review
Latest book: The Well-Grounded Rubyist (http://www.manning.com/black2\)

September Ruby training in NJ has been POSTPONED. Details to follow.

A couple of suggestions.

Firstly, camelCase looks really ugly in Ruby programs so I'm going to inject the underscores in the following comments.

It would make more sense to populate the butter_queue with objects that respond to put_butter_on as these appear to be the message recipients. This would also mean that instead of checking on each access for an empty queue you could either rescue or propagate the NoMethodError when butter_queue.shift produces a nil value.

Taking this idea a step further, butter_up is clearly a method of a ButterQueue object, so the whole might be better expressed as:

class ButterQueue
   def initialize
     @queue =
   end

   def butter_up
     begin
       @queue.shift.but_butter_on
     rescue Exception=> e
       log_message e
       raise
     end
   end
end

I've rewritten the error handling so that it creates a message in the log (assuming log_message to be defined somewhere in scope) and then re-raised it so that the calling code can decide how to handle it. This allows an error to be handled separately from a nil value return as the latter may have some specific semantic meaning.

I hope this all makes sense, but if not I'd be happy to discuss it further off-list.

Ellie

Eleanor McHugh
Games With Brains
http://slides.games-with-brains.net

···

On 10 Sep 2009, at 04:08, Nick Green wrote:

def butterUp butter_queue
return if butter_queue.empty?
begin
   putButterOn butter_queue.shift
rescue err
   logMsg err
   butterUp
end
end

----
raise ArgumentError unless @reality.responds_to? :reason

Hahah, yes I pulled the example completely out of my... well out of thin
air;p I wasn't thinking how one would implement the whole, just trying
to get a feel for error handling. However, your in depth critique of my
culinary function is appreciated, as is your rescue example. I
understand that were it in a bigger program the failsafes would be
elsewhere, but I do think there are cases where, so to speak, "the show
must go on" and I was wondering how best to go about that in ruby. This
thread has more-than-answered my question :slight_smile:

Also, great slides on the link in your sig.

p.s. I like camel case :cry: and i do indeed define logMessage in most of
my code;P

Eleanor McHugh wrote:

···

On 10 Sep 2009, at 04:08, Nick Green wrote:

def butterUp butter_queue
return if butter_queue.empty?
begin
   putButterOn butter_queue.shift
rescue err
   logMsg err
   butterUp
end
end

A couple of suggestions.

Firstly, camelCase looks really ugly in Ruby programs so I'm going to
inject the underscores in the following comments.

It would make more sense to populate the butter_queue with objects
that respond to put_butter_on as these appear to be the message
recipients. This would also mean that instead of checking on each
access for an empty queue you could either rescue or propagate the
NoMethodError when butter_queue.shift produces a nil value.

Taking this idea a step further, butter_up is clearly a method of a
ButterQueue object, so the whole might be better expressed as:

class ButterQueue
   def initialize
     @queue =
   end

   def butter_up
     begin
       @queue.shift.but_butter_on
     rescue Exception=> e
       log_message e
       raise
     end
   end
end

I've rewritten the error handling so that it creates a message in the
log (assuming log_message to be defined somewhere in scope) and then
re-raised it so that the calling code can decide how to handle it.
This allows an error to be handled separately from a nil value return
as the latter may have some specific semantic meaning.

I hope this all makes sense, but if not I'd be happy to discuss it
further off-list.

Ellie

Eleanor McHugh
Games With Brains
http://slides.games-with-brains.net
----
raise ArgumentError unless @reality.responds_to? :reason

--
Posted via http://www.ruby-forum.com/\.

class ButterQueue
def initialize
@queue =
end

def butter_up
begin
@queue.shift.but_butter_on
rescue Exception=> e
log_message e
raise
end
end
end

I've rewritten the error handling so that it creates a message in the log
(assuming log_message to be defined somewhere in scope) and then re-raised
it so that the calling code can decide how to handle it. This allows an
error to be handled separately from a nil value return as the latter may
have some specific semantic meaning.

I find it debatable whether this pattern does make sense: if the
calling code can handle the exception in a meaningful way, there is no
point in logging it, because that would attract suspicion where it is
not in order. I would say that logging is a form of handling, i.e. if
the calling code does not know what to do about it, it can still log
the error. If you log it in the source location then this could be
viewed as violating the principle of "let the calling code decide how
to handle the exception".

One more reason against this pattern: if this is done on multiple
levels you'll get the exact same error multiple times in the log which
does not really help clear things up.

I hope this all makes sense, but if not I'd be happy to discuss it further
off-list.

Please let's keep it on list. We would miss your mellow home brew comments. :slight_smile:

Kind regards

robert

···

2009/9/10 Eleanor McHugh <eleanor@games-with-brains.com>:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

I've rewritten the error handling so that it creates a message in the log
(assuming log_message to be defined somewhere in scope) and then re-raised
it so that the calling code can decide how to handle it. This allows an
error to be handled separately from a nil value return as the latter may
have some specific semantic meaning.

I find it debatable whether this pattern does make sense: if the
calling code can handle the exception in a meaningful way, there is no
point in logging it, because that would attract suspicion where it is
not in order. I would say that logging is a form of handling, i.e. if
the calling code does not know what to do about it, it can still log
the error. If you log it in the source location then this could be
viewed as violating the principle of "let the calling code decide how
to handle the exception".

Possibly, although there are cases where having subsystems log unusual occurrences for later analysis can be useful and it's also quite a nice pattern for triggering fail-safe behaviours at the right level of encapsulation when they are necessary. The caveat being that I very rarely find myself writing production code where that's necessary.

One more reason against this pattern: if this is done on multiple
levels you'll get the exact same error multiple times in the log which
does not really help clear things up.

I wouldn't recommend using it at multiple levels unless each triggered different behaviour, or the triggered behaviour was clever enough to filter and distil. That may or may not be compatible with good data encapsulation depending on the problem domain.

I hope this all makes sense, but if not I'd be happy to discuss it further
off-list.

Please let's keep it on list. We would miss your mellow home brew comments. :slight_smile:

Oh to see ourselves through the eyes of others...

Ellie

Eleanor McHugh
Games With Brains
http://slides.games-with-brains.net

···

On 14 Sep 2009, at 08:43, Robert Klemme wrote:
----
raise ArgumentError unless @reality.responds_to? :reason