How to react on nil or wrong object-type as parameter

Hi,

I was just wondering: how do I react on a method-invocation with a
nil-object instead of eg. String? How do I test it? And how can I assure
that it is the right kind of object?

class AClass
def a_method aString
puts aString+aString
puts aString.reverse
end

end

an_object = AClass.new
an_object.a_method “hello” # works
an_object.a_method 3#-> undefined method
an_object.a_method nil #-> undefined method

Does Duck-Typing mean “ah, the programmer always knows, which kind of
objects this method expects. Thus never an error will occur.”? This
seems very optimistic to me if not naiv. You cant just trust that the
any programmer who uses your class knows what exactly is happening in
your method and which type of object is required.

Thankful for any hint.

Regards,
Yochen

Yochen G. wrote:

end

end

an_object = AClass.new
an_object.a_method “hello” # works
an_object.a_method 3#-> undefined method
an_object.a_method nil #-> undefined method

I’d do it like this:

class SomeClass
def foo(obj)
str = obj.to_str
puts str + str # or `str * 2’
puts str.reverse
end
end

Though I know some very smart people on this list disagree with me.

Cheers,
Daniel

Hi Daniel,

Daniel S. wrote:

class SomeClass
def foo(obj)
str = obj.to_str
puts str + str # or `str * 2’
puts str.reverse
end
end

this might work in this very simple expample, but what if

class SomeMonsterousClass

def very_complexe_method a_very_complicated_obejct
a_very_complicated_obejct.do_something
lots_of_other_operations
lots_of_other_operations
lots_of_other_operations
lots_of_other_operations

end
end

So here you cant just convert any given object to
a_very_complicated_object. By the way your solution would not work with
nil.

Nevertheless, thank you for your support.

Greetings,
Yochen

On 8/6/06, Yochen G. [email protected] wrote:

 puts aString.reverse

Does Duck-Typing mean “ah, the programmer always knows, which kind of
objects this method expects. Thus never an error will occur.”? This
seems very optimistic to me if not naiv. You cant just trust that the
any programmer who uses your class knows what exactly is happening in
your method and which type of object is required.

Thankful for any hint.

Well what a nice occasion. I have to reply fast because I will be
outnumbered fast :wink:
I have for quite a while now spoken up for some mechanisms for
defensive
programming and early failure, without success so far.
What you can do e.g. is

def aMethod something
raise WhateverException, “whatever info useful” unless String ===
something

you might also distinguish sometimes between nil and other problems

However I have to conceede a point to the ducktypers (which is quite a
nice
feature I never want to see disappear) sometimes
you want something to reply to #reverse and to #+, ( a String object
might
not reply to these messages ).

So you could just fail or fail with a more meaningful message like this
raise GreatExplanation, “sage sayings” unless
something.respond_to?:reverse

I still think it would be great to have an expressive syntax about this
like
e.g;

def act actor : Actor
def act actor is Actor
def act actor where Actor === actor
def act actor : SomeThing

note that SomeThing could also be a module and ruby should check if the
instance methods of SomeThing are replied to by actor.
Thus just doing kind of an automated duck type check.

Hope you do not mind using your thread for some lobbying :slight_smile:

Cheers
Robert

Regards,
Yochen


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


Deux choses sont infinies : l’univers et la bêtise humaine ; en ce qui
concerne l’univers, je n’en ai pas acquis la certitude absolue.

  • Albert Einstein

Hi Yochen,

Yochen G. wrote:

end

So here you cant just convert any given object to
a_very_complicated_object.

Why not? I usually do this:

class ComplicatedObject
def to_complicated_object
self
end
end

By the way your solution would not work with
nil.

Why not? It would complain that nil doesn’t respond to #to_str. You
could expand it to this:

def foo(obj)
unless obj.respond_to? :to_str
raise ArgumentError, “argument must be a string”
end

 str = obj.to_str

 ...

end

Cheers,
Daniel

On 6-aug-2006, at 17:52, Yochen G. wrote:

unless obj.respond_to? :to_str,:another_method, :yet_another_method,
:and_again_another_method

basically it’s easy (and common) to raise in such a case, but there
is a quick plumbing trick

def explode_reactor(bomb)
bomb.activate rescue nil
end

This will activate the bomb and return nil if it raises (as the thing
raised will most likely be a NoMethodError).

def foo(obj)
unless obj.respond_to? :to_str
raise ArgumentError, “argument must be a string”
end

 str = obj.to_str

 ...

end
I see, but if it is a long method I might end up with

unless obj.respond_to? :to_str,:another_method, :yet_another_method,
:and_again_another_method

and so on. This seems to be one of the only ways to make it secure.
Another way would be to wrap a begin/rescue around the whole method-body
to capture all possibly arrising ArgumentErrors. Am I right with this?

Ahoi,
Yochen

On Aug 6, 2006, at 11:05 AM, Yochen G. wrote:

  ...

end
end

So here you cant just convert any given object to
a_very_complicated_object. By the way your solution would not work
with
nil.

I think Meyers’ Design by Contract (DBC) ideas are helpful in talking
about
this situation.

In DBC terminology, you are asking about how to handle a caller who
violates
a method’s preconditions. This is a bug in the caller. A correctly
written
caller would never violate the precondition. You basically have two
choices:

1) fix the bug by correcting the code in the caller to meet
        the pre-condition of the method
2) loosen the pre-condition of the method so that the call is valid

Generally I think that 1) is the correct approach and that a good
testing
framework will help you discover and correct these types of bugs.
Adding lots of checks and raising exceptions in the method itself is too
little, too late. Your testing framework is a better place to spend
the effort of detecting and correcting errors like that.

Sometimes 2) is the better approach. There are some Ruby idioms that
are helpful in this situation. For example, the practice of calling
to_s on an
argument that will be output in some text format instead of insisting
that
the caller convert the object to a string. Similarly for to_a,
to_i, or
to_proc.

Gary W.

Yochen G. wrote:

unless obj.respond_to? :to_str,:another_method, :yet_another_method,
:and_again_another_method

Yes, that’s true. But then again, all objects that respond to those
messages can be used as arguments to your method, thus increasing the
flexibility of your application dramatically.

Oftentimes, it isn’t necessary to use #respond_to?. Simply call the
methods on the received argument – if an exception is raised, you can
easily debug. e.g.

nil.foo

=> test.rb:11: undefined method `foo’ for nil:NilClass (NoMethodError)

Here you get the line number the error occurred on (11), the kind of
exception raised (NoMethodError), the message not responded to (#foo),
and what kind of object the message was sent to (nil).

Another way would be to wrap a begin/rescue around the whole method-body
to capture all possibly arrising ArgumentErrors. Am I right with this?

You could do it like this:

def foo(obj)
foo.bar!
rescue NoMethodError => error
puts “argument must respond to #{error.name}”
end

Although this has the downside that it’ll rescue all such exceptions,
even those caused by your own mistakes.

Cheers,
Daniel

Robert K. wrote:

No, duck typing means you just use those methods needed and if the type
doesn’t match the caller gets bitten by an exception. You should of
course document what the method does. For example (silly method)

Exactly. Your tossing one of the primary advantages of a language like
Ruby out the window if you load your code up with all kinds of type
checking. Why try and decide for every future caller what part of your
code may be functional for their (unknown to you) purpose. Document
what your code does, let the exceptions fly.

Instead of defensive coding write decent automated tests to make sure
you expect

Yochen G. wrote:

Does Duck-Typing mean “ah, the programmer always knows, which kind of
objects this method expects. Thus never an error will occur.”? This
seems very optimistic to me if not naiv. You cant just trust that the
any programmer who uses your class knows what exactly is happening in
your method and which type of object is required.

No, duck typing means you just use those methods needed and if the type
doesn’t match the caller gets bitten by an exception. You should of
course document what the method does. For example (silly method)

appends using “<<”

def append(s,x) s << x end

can be invoked with a String or IO or Array etc. as first parameter.
But if you pass nil you’ll see an exception.

Type checks are done rather rarely. The other way to do is what Daniel
showed (a lot core classes do this AFAIK).

Kind regards

robert

Yochen G. wrote:

So if I do understand you all correctly, in Ruby you put the responsible
to the caller of a method (eg print_salary()). If you want to test that
method, you test it only with the proper types. The next thing would be
testing the method which includes the call of print_salary() if it calls
this methods with the wrong types of parameter. Is this right?

One problem in this concept is that if some operations might work on a
parameter-object and the following is not the exception is thrown when
the object is already modified.

class Bank
@invitations_to_golf

def handle_client_well client
client.decrease_acoount(200)
client.check_portfolio
@invitations_to_golf.push client
end

end

jon_doe = LowBudgetClient.new
big_boss = VeryRichClient.new
big_money = Bank.new

big_money.handle_client_well big_boss
big_money.handle_client_well jon_doe // poor guy has no portfolio

So, when the hcw-method is called with jon_doe, he has to pay for better
handling but since he has no portfolio the exception is thrown before he
is entering the golf course.

One solution might be a exception around the method-body (yes, again
;-)) and a include an ensure to increase the account again if something
broke. But again, this procedure would fail if there are many modifing
operations.

Perhaps I am still thinking too Java’ish and these are high theorectical
problems or I still dont get it.

Yochen

Is it by design that you intend to call handle_client with objects that
don’t have portfolios? Then you need to either check for that in
handle_clients or expect the exception and catch it where it’s called.

If you didn’t intend to call handl_client with a non-portfolio baring
client than the best thing that can happen is raising an expcetion

I’m not really sure I get the conflict you were trying to get to?

So if I do understand you all correctly, in Ruby you put the responsible
to the caller of a method (eg print_salary()). If you want to test that
method, you test it only with the proper types. The next thing would be
testing the method which includes the call of print_salary() if it calls
this methods with the wrong types of parameter. Is this right?

One problem in this concept is that if some operations might work on a
parameter-object and the following is not the exception is thrown when
the object is already modified.

class Bank
@invitations_to_golf

def handle_client_well client
client.decrease_acoount(200)
client.check_portfolio
@invitations_to_golf.push client
end

end

jon_doe = LowBudgetClient.new
big_boss = VeryRichClient.new
big_money = Bank.new

big_money.handle_client_well big_boss
big_money.handle_client_well jon_doe // poor guy has no portfolio

So, when the hcw-method is called with jon_doe, he has to pay for better
handling but since he has no portfolio the exception is thrown before he
is entering the golf course.

One solution might be a exception around the method-body (yes, again
;-)) and a include an ensure to increase the account again if something
broke. But again, this procedure would fail if there are many modifing
operations.

Perhaps I am still thinking too Java’ish and these are high theorectical
problems or I still dont get it.

Yochen

IMHO handle_client_well is simply bad code that needs to be fixed. It
needs to be rewritten into something like:

def handle_client_well client
   if client.check_portfolio then
      client.decrease_acoount(200)
      @invitations_to_golf.push client
   end
end

Further, check_portfolio must be rewritten to return true if the
clients portfolio entitles him to be “well handled”.

When the code is fixed, the kinds of problems you anticipate don’t
occur.

Regards, Morton

Michael G. wrote:

Is it by design that you intend to call handle_client with objects that
don’t have portfolios? Then you need to either check for that in
handle_clients or expect the exception and catch it where it’s called.

If you didn’t intend to call handl_client with a non-portfolio baring
client than the best thing that can happen is raising an expcetion

I’m not really sure I get the conflict you were trying to get to?

Sorry Michael, that I didnt make myself clearer. Yes, it is not intendet
that such a non-portfolioed client can be called upon
handle_client_well. Thus the question is how to aovid this wrong usage.
Seemingly it cant (or at least only through a vast of checkings)).

Greetings,

Yochen

On Aug 6, 2006, at 7:55 AM, Daniel S. wrote:

end
an_object = AClass.new
an_object.a_method “hello” # works
an_object.a_method 3#-> undefined method
an_object.a_method nil #-> undefined method

I’d do it like this:

class SomeClass
def foo(obj)
str = obj.to_str

Don’t call to_str, call to_s.

  puts str + str # or `str * 2'
  puts str.reverse
end

end

Though I know some very smart people on this list disagree with me.

Only because you call to_str. This is not the reason it exists.


Eric H. - [email protected] - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

Eric H. wrote:

 puts aString.reverse
def foo(obj)

Only because you call to_str. This is not the reason it exists.

I favor using #to_str when I want to treat an object like a string.
Practically all classes implement #to_s, so it’s not really a type
restriction. We’re trying to solve two different problems – I want to
let the caller know if he sent the wrong kind of object as an argument.
That’s type checking. If you want to convert any object received to a
string, then we’re talking type conversion, which I think should be left
to the caller in many cases. But that’s just my humble opinion, of
course.

Cheers,
Daniel

On Aug 7, 2006, at 5:37 PM, Yochen G. wrote:

Sorry Michael, that I didnt make myself clearer. Yes, it is not
intendet
that such a non-portfolioed client can be called upon
handle_client_well. Thus the question is how to aovid this wrong
usage.
Seemingly it cant (or at least only through a vast of checkings)).

There is no way to magically prevent incorrect code from being written.
You are framing the problem as if you want to detect the incorrect code
at run time (i.e., when the code is in production) but it is too late
to do anything about incorrect code at that point.

Presumably you want to detect incorrect code before your code is
running
in production. In a dynamic language you have to do that via a good
testing
methodology since you don’t have a compilation step to help you detect
obviously incorrect code. Just to be clear, you have to do testing in
a static/compiled language environment also since not all usage
errors can
be detected via compile-type checks.

Gary W.

-----BEGIN PGP SIGNED MESSAGE-----

In article [email protected],
Yochen G. [email protected] wrote:

Sorry Michael, that I didnt make myself clearer. Yes, it is not intendet
that such a non-portfolioed client can be called upon
handle_client_well. Thus the question is how to aovid this wrong usage.
Seemingly it cant (or at least only through a vast of checkings)).

_ If you really think this kind of checking is important, then
don’t use Ruby. Languages are just tools and not every tool works
for every job. Exception catching generally works well enough and
if you haven’t used this style of error checking before, then it
takes some getting used to. Ruby is not everybody’s cup of tea.

_ Objective C has the concept of “interfaces” in which you define
a set of methods that you respond to and you can do things like
ask if an object implements that interface. I think there are
various Ruby modules out there that implement similar
concepts. It wouldn’t be all that hard to write a module to
do this.

_ Ruby is like most object based systems, it makes coding easy,
but punishes you for design mistakes. The kind of typing you
want to me is a red flag for a weak design. What I’ve
found in my experience with Ruby is that if I’m having problems
with this kind of thing, it’s almost always a sign that my design
needs work.

_ Booker C. Bense

-----BEGIN PGP SIGNATURE-----
Version: 2.6.2

iQCVAwUBRNfCwGTWTAjn5N/lAQFIugP9FwfYKRrcqfI2N9JD1JZwavKCWqSZmDWR
ZUj7LWXDUyZPXsZaNKk9dA8EoSKlqzaBzefQZuJsXJBY7kibt6Uevp/uPWxRF/oz
89dgL6GgtzQNx19D6buGgyArt4d51Kozf8c4Pr9aTTpAAT0PIlbROxov6Ba2bNVP
kgizeguS6q0=
=lbIo
-----END PGP SIGNATURE-----

On Aug 7, 2006, at 3:30 PM, Daniel S. wrote:

end

received to a string, then we’re talking type conversion, which I
think should be left to the caller in many cases. But that’s just
my humble opinion, of course.

#to_str is not for type conversion. It exists for classes that duck
type completely to String and is called when a C string is needed by
a method in String to improve performance. In other words, #to_str
should only be implemented on objects that are already “Strings”.

#to_s is for type conversion. Trust your users to provide a
meaningful #to_s. Don’t force them to inappropriately implement
#to_str.


Eric H. - [email protected] - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs