Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Type checking function parameters

3 views
Skip to first unread message

Nick Green

unread,
Sep 3, 2009, 12:04:53 AM9/3/09
to
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/.

Eleanor McHugh

unread,
Sep 3, 2009, 4:49:20 AM9/3/09
to

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

unread,
Sep 3, 2009, 8:57:05 AM9/3/09
to
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.

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

pa...@pollyandpaul.co.uk

Nick Green

unread,
Sep 3, 2009, 6:47:28 PM9/3/09
to
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.duc...@notarealemail.com. Make sure to include the
following: <normal error dump>"?

Eleanor McHugh

unread,
Sep 3, 2009, 8:30:02 PM9/3/09
to
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.duc...@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.

James Edward Gray II

unread,
Sep 3, 2009, 10:56:56 PM9/3/09
to

That was so beautiful I almost teared up. ;)

James Edward Gray II


Eleanor McHugh

unread,
Sep 4, 2009, 2:45:16 PM9/4/09
to

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

spiralofhope

unread,
Sep 6, 2009, 12:33:10 AM9/6/09
to
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


Josh Cheek

unread,
Sep 6, 2009, 1:36:31 AM9/6/09
to
[Note: parts of this message were removed to make it a legal post.]

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.

David A. Black

unread,
Sep 6, 2009, 7:56:52 AM9/6/09
to
Hi --

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

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

Eleanor McHugh

unread,
Sep 6, 2009, 9:58:31 AM9/6/09
to
On 6 Sep 2009, at 12:56, David A. Black wrote:
> 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);

Indeed the fact that both classes and objects are open and can have
methods added, removed or replaced at any point during runtime
execution means that even if a method checks to ensure that one of its
parameters is for example a String object, that object may well not
have the full complement of methods defined by the String class at the
time code seeks to manipulate it and hence could still raise a
MethodMissing exception.

Locking down object identity is therefore a cumbersome approach to
type safety that sacrifices much of the flexibility that makes Ruby a
pleasure to work with, but in those rare cases where it might seem
desirable good practice is to filter based upon responds_to not about
Class identity. In general though code will be more robust if the
emphasis is placed on good exception handling and testing rather than
type checking.

Nick Green

unread,
Sep 7, 2009, 3:12:25 AM9/7/09
to
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

Josh Cheek

unread,
Sep 7, 2009, 3:47:08 AM9/7/09
to
[Note: parts of this message were removed to make it a legal post.]

> Maybe something like this:


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.

Bill Kelly

unread,
Sep 7, 2009, 3:57:52 AM9/7/09
to

From: "Josh Cheek" <josh....@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.


Regards,

Bill


David A. Black

unread,
Sep 7, 2009, 6:36:58 AM9/7/09
to
Hi --

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

David A. Black

unread,
Sep 7, 2009, 6:41:37 AM9/7/09
to
Hi --

On Mon, 7 Sep 2009, Nick Green 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?)

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.

Nick Green

unread,
Sep 9, 2009, 11:08:12 PM9/9/09
to
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.

Eleanor McHugh

unread,
Sep 10, 2009, 8:14:13 AM9/10/09
to
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.

Nick Green

unread,
Sep 13, 2009, 8:52:08 PM9/13/09
to
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 :)

Also, great slides on the link in your sig.

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

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

Robert Klemme

unread,
Sep 14, 2009, 3:43:49 AM9/14/09
to
2009/9/10 Eleanor McHugh <ele...@games-with-brains.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 :-)

Kind regards

robert

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

Eleanor McHugh

unread,
Sep 14, 2009, 9:27:01 AM9/14/09
to
On 14 Sep 2009, at 08:43, Robert Klemme wrote:
>> 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. :-)

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

Nick Green

unread,
Sep 16, 2009, 10:13:23 PM9/16/09
to
I think you guys are fairly over my head in this discussion, but my 2
cents for the logging question: I always make my loggy function log
with a prefix indicating severity/type of log message, i.e. the usual
[INFO], [DEBUG], [ERROR], and maybe an occasional [TOOBVIOUSTOLOG] or
[OMGWEARESOTOTALLYSCREWED] for good measure. This lets you fairly
trivially cat/grep/redirect or whatever you method of choice is to get
only the log levels you care about when checking the log, and makes
turning logging off for given categories fairly easy (just a change to
the log function, or ideally have the log function know what
"environment" its running in). Anywho, dunno how this scales, I can get
away with it in C but maybe inefficiency would be a problem in a
multi-user app if you did this with ruby.

Our particular culinary message might deserve an [INFO], but more likely
would get stuck with the [DEBUG] so it could be turned off once I was
confident in my buttering logic.

P.S. upon further reading (I really don't know how I so thoroughly
missed begin/rescue/else/ensure/end magic in my initial round of ruby
tutorials!), I've found there are a few good ways to handle this
situation:)

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

0 new messages