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

···

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

Yochen Gutmann wrote:

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

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,

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.

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

···

On 8/6/06, Yochen Gutmann <yoche2001@dergutemann.com> wrote:

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

Yochen Gutmann 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

Hi Daniel,

Daniel Schierbeck 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

···

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

Robert Klemme 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

···

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

Yochen Gutmann wrote:

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

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.

···

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

--
Eric Hodel - drbrain@segment7.net - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

Hi Yochen,

Yochen Gutmann wrote:

class SomeMonsterousClass

   def very_complexe_method a_very_complicated_obejct
     a_very_complicated_obejct.do_something
     lots_of_other_operations
      ...
   end
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

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 Wright

···

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

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

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

···

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

Eric Hodel wrote:

Yochen Gutmann wrote:

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

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.

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 6, 2006, at 7:55 AM, Daniel Schierbeck wrote:

   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

···

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

Yochen Gutmann 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?

···

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

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

···

On Aug 7, 2006, at 4:37 PM, Yochen Gutmann 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

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

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.

Where type may not be related to the Object's class or inheritance tree.
An object's type for any method call is explicitly related to whether it
responds to the method we're looking for with the arguments we provide
and the sort of return value we're wanting. It's significantly different
than Java in this way.

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?

Um, not really as I understand it.

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.

There are problems with your example code:

class Bank
   @invitations_to_golf

This won't do what you expect. Try:

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

end

  class Bank
    def initialize
      @invitations_to_golf =
    end

    def issue_golf_invitations(title, sender, message, date)
      @invitations_to_golf.each { |client|
        client.send_message title, sender, message, date
      }
    end

    def treat_client_well(client)
      if client.check_portfolio
        client.decrease_account(200)
        @invitations_to_golf << client
      end
    end
  end

What this does is that it requires that all clients have a
#check_portfolio method. If the Bank's clients aren't guaranteed to have
that, you'll blow up here, as you've suggested. But how do you deal with
that? Well, you don't look for a VeryRichClient. You do one of two
things:

  class Client
    def check_portfolio
      nil
    end
  end

  class LowBudgetClient < Client
  end

  class VeryRichClient < Client
    def check_portfolio
      true
    end
  end

So you modify the object you're dealing with and expect to pass in so
that it always has a check_porfolio (that's why I put the "if" test,
which you'd want anyway) or you do:

  class Bank
    def treat_client_well(client)
      if client.respond_to?(:check_portfolio) and client.check_portfolio
        client.decrease_account(200)
        @invitations_to_golf << client
      end
    end
  end

Or you handle your call a bit better:

   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 rescue nil

One need not be explicit about how you handle a lot of things in Ruby.
Strictly speaking, you'd *never* want to have two classes for clients in
this way, but you may have things in the contents of the clients which
allow you to do things smarter.

-austin

···

On 8/7/06, Yochen Gutmann <yoche2001@dergutemann.com> wrote:
--
Austin Ziegler * halostatue@gmail.com * http://www.halostatue.ca/
               * austin@halostatue.ca * You are in a maze of twisty little passages, all alike. // halo • statue
               * austin@zieglers.ca

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

···

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

Eric Hodel wrote:

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

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.

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.

--
Eric Hodel - drbrain@segment7.net - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

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

···

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

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

--
Julian 'Julik' Tarkhanov
please send all personal mail to
me at julik.nl

Yochen Gutmann wrote:

   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

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

Michael Greenly 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

···

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

Eric Hodel wrote:

Eric Hodel wrote:

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.

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.

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

Exactly my point. I think we're misunderstanding each other here; if you have an object that is a representation of a string, say

   # Bad example, but hey...
   class Name
     attr_accessor :first, :last

     def initialize(first, last)
       @first, @last = first, last
     end
   end

Then it's okay for it to have #to_str, e.g.

     def to_str
       "#{first} #{second}"
     end

My own logic is this: if an object is a natural string, but with *more* information, then it can have #to_str. Otherwise, stick to #to_s.

A much better example is the one brought up on the list not long ago:

   class RomanNumeral
     def initialize(num)
       @num = num.to_int
     end

     # this really is an integer
     def to_int
       @num
     end

     # but there's not much sense in manipulating
     # it as a string
     def to_s
       ...
     end
   end

If it were for a real application, I'd just implement an Integer#to_roman method, but I still think this is a good example.

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

I agree wholeheartedly. I'm just bad at writing.

···

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

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