The duck's backside

Hi,
as a newcomer I miss method overloading with named parameters and types
(Objective-C!). Mainly because my code is riddled with ugly “case
argument.class” and “raise unless Integer”. But maybe that’s the
problem.

What is the Duck way to check arguments? I have to because I’m passing
on to a rather fragile web service.

I only need numbers (ids) and strings in my instance variables, but
considered making a class for each one to catch illegal data in
initialize.

2008/5/28 Tobias W. [email protected]:

as a newcomer I miss method overloading with named parameters and types
(Objective-C!). Mainly because my code is riddled with ugly “case
argument.class” and “raise unless Integer”. But maybe that’s the problem.

You cannot expect to carry your Objective-C style of programming over
to Ruby. Instead, if you want to have overloading you need to either
use different method names (appropriate if the overloaded methods act
differently) or you can do it with a single method (e.g. if the
overloading was just there to adjust type - for example on version
accepts an int and another accepts a float and internally you continue
processing with a float).

What is the Duck way to check arguments? I have to because I’m passing
on to a rather fragile web service.

The duck way is to not check arguments.

I only need numbers (ids) and strings in my instance variables, but
considered making a class for each one to catch illegal data in
initialize.

It’s difficult to answer on such a general scale. Usually, if there
are particular requirements you have on arguments passed to methods
you should check inside the method that receives them. Note, that for
integers there is to_int so you can do:

class Foo
def doit length
@l = length.to_int
end
end

Can you give a more concrete example?

Kind regards

robert

On 28 May 2008, at 11:01, Tobias W. wrote:

raise ArgumentError, “need exactly one number”
end
@http.post(“first=#{a}&second=#{b}&third=#{c}”)
end

This is off the top of my head so the usual caveats apply:

def doit a, b, c = nil
begin
case
when b && c
raise
when b && b.respond_to?(:to_int)
uaid = “ignore” if b.to_int > 0
when c && c.respond_to?(:to_int)
c = “ignore” if c.to_int > 0
else
raise
end
rescue
raise ArgumentError, “need exactly one number”
end
@post(“first=#{a}&second=#{b.to_int}&third=#{c.to_int}”)
end

This makes the exclusion of b and c more explicit, which will make it
much easier for a maintainer to understand what’s going on. I’ve also
made integer conversion explicit and focused the filtering logic on
making sure it’s appropriate as that’s what you’re really trying to
achieve, however this kind of belt-and-braces approach suggests that
you’re tackling the problem from the wrong angle and should look at
the data-flow elsewhere in your code.

One possibility would be to rejig the whole thing as follows:

def doit a, v, param = :second
raise ArgumentError, “needs a numeric value” unless v.respond_to?
(:to_int)
v = “ignore” if (param == :third) && v > 0
@post(“first=#{a}&second=#{v if param == :second}&third=#{v if param
== :third}”)
end

and then evolve it from there, although it’s also pretty damn ugly.

Where this is called you could write something along the lines of:

if b && c then
raise ArgumentError, “needs exactly one additional argument”
else
doit a, (b || c), (b.nil? ? :third : :second)
end

which could be further encapsulated as:

doit a, b, c = nil
raise ArgumentError, “needs exactly one additional argument” if b &&
c
v = b || c
raise ArgumentError, “need a numeric parameter” unless v.respond_to?
(:to_int)
param = b.nil? ? :third : :second
v = “ignore” if (param == :third) && v > 0
@post(“first=#{a}&second=#{v if param == :second}&third=#{v if param
== :third}”)
end

Ellie

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

raise ArgumentError unless @reality.responds_to? :reason

On Wed, May 28, 2008 at 9:45 AM, Tobias W. [email protected] wrote:

The first idea would be to do something like the following

module MyChecker
MyConstraintError = Class::new RuntimeError

def make_ivar name, value, *allowedClasses
    raise MyConstraintError, "...." unless
        allowedClasses.any?{ |klass| klass === value }
    instance_variable_set name, value
end

end

class MyClass
include MyChecker
def initialize int_val, str_val, val
make_ivar :@int, int_val, Integer
make_ivar :@str, str_val, String
make_ivar :@var, val, Integer, String

HTH
Robert


http://ruby-smalltalk.blogspot.com/


Whereof one cannot speak, thereof one must be silent.
Ludwig Wittgenstein

In article
[email protected],
Robert K. [email protected] wrote:

differently) or you can do it with a single method (e.g. if the
overloading was just there to adjust type - for example on version

And if the types are rather different ducks, would you “case type”?

are particular requirements you have on arguments passed to methods
you should check inside the method that receives them. Note, that for

Yes, but it’s uuugly :wink:

def doit length
@l = length.to_int
end

Nice, I had forgotten about that one, and to_i won’t do as even nil
answers to it.

Can you give a more concrete example?

def doit(a, b, c = nil)
begin
if c.nil? and b > 0
c = “ignore”
elsif b.nil? and c > 0
uaid = “ignore”
else
raise
end
rescue RuntimeError, NoMethodError
raise ArgumentError, “need exactly one number”
end
@http.post(“first=#{a}&second=#{b}&third=#{c}”)
end

In article
[email protected],
Eleanor McHugh [email protected] wrote:

 uaid = "ignore"

Ups, shoulda been c =

@post("first=#{a}&second=#{b.to_int}&third=#{c.to_int}")

Won’t work as the web service actually expects either a number or the
string “ignored”

This makes the exclusion of b and c more explicit, which will make it

First I actually tried exclusive or, but that operates bit-wise on
Integer so the results were strange.

I’ve always been very comfortable with perl’s boolean logic, so I have
to relearn some tricks.

(in Ruby 0 and “” are true)

achieve, however this kind of belt-and-braces approach suggests that
you’re tackling the problem from the wrong angle and should look at
the data-flow elsewhere in your code.

So that doit() is only passed legal values? That should be the case, but
I want to make extra sure not to give that foreign web service something
it can’t swallow.

def doit a, v, param = :second
raise ArgumentError, “needs a numeric value” unless v.respond_to?
(:to_int)
v = “ignore” if (param == :third) && v > 0

That is essentially overloading doit() for first or second parameter,
and a good idea! So far I just wrapped the http calls in convenience
methods one by one.

On 28 Mai, 15:14, Tobias W. [email protected] wrote:

Won’t work as the web service actually expects either a number or the
string “ignored”

You can do

@post(“first=#{a}&second=#{b.to_int rescue ‘ignored’}&third=#{c.to_int
rescue ‘ignored’}”)

Of course, defining a method for this would be better. How about:

def intify(x)
x.to_int rescue “ignored”
end

def doit(a, b, c = nil)
(b, c = intify(b), intify(c)).select {|x| Numeric === x}.size != 1
and
raise ArgumentError, “need exactly one number”
@http.post(“first=#{a}&second=#{b}&third=#{c}”)
end

Cheers

robert

On 28 May 2008, at 14:15, Tobias W. wrote:

In article
[email protected],
Eleanor McHugh [email protected] wrote:

uaid = "ignore"

Ups, shoulda been c =

Which makes things simpler :wink:

doit a, b, c = nil
raise ArgumentError, “needs exactly one additional argument” if b &&
c
v = b || c
raise ArgumentError, “need a numeric parameter” unless v.respond_to?
(:to_int)
@post “first=#{a}&” + (b.nil? ? “second=ignored&third=#{v}” :
“second=#{v}&third=ignored”)
end

That is essentially overloading doit() for first or second parameter,
and a good idea! So far I just wrapped the http calls in convenience
methods one by one.

I’m not suggesting it’s a good idea…

Ellie

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

raise ArgumentError unless @reality.responds_to? :reason

Tobias,

as a newcomer I miss method overloading with named parameters and types
(Objective-C!). Mainly because my code is riddled with ugly “case
argument.class” and “raise unless Integer”. But maybe that’s the problem.

What is the Duck way to check arguments? I have to because I’m passing
on to a rather fragile web service.

Don’t bother. Use your arguments, assuming they are the correct type.
If they are not, then a runtime exception will be thrown. Unless the
input to this function is coming from an untrusted source, the inputs
will always be the correct type. If they are not, then something is
seriously wrong.

Jim

On May 28, 2008, at 8:24 AM, Eleanor McHugh wrote:

doit a, b, c = nil
raise ArgumentError, “needs exactly one additional argument” if b
&& c
v = b || c
raise ArgumentError, “need a numeric parameter” unless
v.respond_to?(:to_int)
@post “first=#{a}&” + (b.nil? ? “second=ignored&third=#{v}” :
“second=#{v}&third=ignored”)
end

This looks like a great solution!

But if you want to check for numeric parameters, would it be better
just to use Numeric === v ? I know this isn’t the ducky way, but it
certainly seems more “intentional.”

///ark

On 28 May 2008, at 18:57, Mark W. wrote:

This looks like a great solution!

But if you want to check for numeric parameters, would it be better
just to use Numeric === v ? I know this isn’t the ducky way, but it
certainly seems more “intentional.”

That’d be marginally more readable but to my mind it’s overly
cautious: what’s the point of using Ruby if you’re still going to
follow static typing conventions?

Ellie

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

raise ArgumentError unless @reality.responds_to? :reason

On May 28, 2008, at 11:45 AM, Eleanor McHugh wrote:

But if you want to check for numeric parameters, would it be better
just to use Numeric === v ? I know this isn’t the ducky way, but it
certainly seems more “intentional.”

That’d be marginally more readable but to my mind it’s overly
cautious: what’s the point of using Ruby if you’re still going to
follow static typing conventions?

The only point of using Ruby (or any other tool in the universe) is to
get a job done. :slight_smile: I would never use a Ruby feature just because Ruby
makes it possible.

Numeric === v is not a static typing convention (see
Type system - Wikipedia)
. It’s just OOP. It says in computer-understandable terms exactly what
you expressed in English: “v is numeric.”

I don’t even know what the ability to respond to :to_int means. Does
that mean the entity is numeric? Does a numeric string qualify? Does a
floating point number qualify? Could Array support this method? Does
every class that responds to to_int do semantically equivalent things?
(think Cowboy#draw and Artist#draw). The only way to tell is to test
it or look it up. This doesn’t make it “marginally” less readable than
Numeric === v, IMO.

Different strokes, of course…

///ark

On Wednesday 28 May 2008 15:09:23 Mark W. wrote:

On May 28, 2008, at 11:45 AM, Eleanor McHugh wrote:

That’d be marginally more readable but to my mind it’s overly
cautious: what’s the point of using Ruby if you’re still going to
follow static typing conventions?

The only point of using Ruby (or any other tool in the universe) is to
get a job done. :slight_smile: I would never use a Ruby feature just because Ruby
makes it possible.

Put it this way: What’s the point of using, say, Erlang, if you never
use its
concurrency features?

Granted, Ruby has a bit more going for it, but a lot of the joy of using
Ruby
is how much less work you end up having to do when you don’t have to
think
about types too much.

. It’s just OOP. It says in computer-understandable terms exactly what
you expressed in English: “v is numeric.”

No, it says “v is of class Numeric.” It’s very explicit, and makes the
assumption that anything which acts like a number will eventually
inherit
from Numeric.

I don’t even know what the ability to respond to :to_int means.

I think it would be :to_i, actually… And I’d probably just call
foo.to_i,
rather than testing for the existence of to_i.

Another possibility is: v.integer?

Does
that mean the entity is numeric?

In a sense.

Does a numeric string qualify?

Yes, it’ll be parsed.

Does a
floating point number qualify?

Yes, it’ll be rounded down.

Could Array support this method?

Anything could. Open classes mean you could add one to Array. But out of
the
box, it doesn’t appear to.

Does
every class that responds to to_int do semantically equivalent things?

Probably – to_i is very much baked into the language, along with to_s
and
friends.

Remember the above – I could actually completely redefine Array, or
Numeric,
etc. So even your assumption that “Numeric === foo” tests for Numeric is
really only based on convention – you’re assuming that no one, anywhere
in
your code, is doing stuff like this:

Numeric = nil

(think Cowboy#draw and Artist#draw).

Yes, that is a downside of duck typing, as currently implemented, but
doesn’t
really apply to :to_i.

Also, context matters. If Cowboy and Artist are both in a GUI widget
library,
that Cowboy is asking for trouble. And it’s worth asking how the Cowboy
came
to be in an art studio, or how the Artist came to be in a saloon –
there are
likely going to be more elegant solutions than

if Cowboy === bill

On Wednesday 28 May 2008 16:25:15 John C. wrote:

class MyObject

def initialize( _a, _b, _c)
@a = _a.quacks_like( :qwaak, :waddle, :swim)
@b = _b.static_type_check String
@c = _c.polymorphic_type_check MyBaseClass
end

Without the checks above, the exceptions would be thrown here, with the

buggyline nowhere on the backtrace!

def my_use
@a.qwaak( @b) + @c
end
end

I’m fine with that, because 99% of the time, I’ll never hit that
exception.
When I do, it’s usually possible to deal with it – in this case, you
would
find where @a is set, and add a check there.

I think you’re arguing to add that check first. I would call that
premature
strictness – but if you have to do it, I like your way.

Oh, also: Most of the time, I use setters/getters (attr_accessor), even
when
something’s mostly going to be internal. That simplifies this process –
I
know there was a problem with a, so I can override a’s setter with
something
that performs the same check. But that’s also probably overkill – if a
class
can’t fit on a page, it’s probably too big and should be broken down.

On Thu, 29 May 2008, Jim M. wrote:

What is the Duck way to check arguments? I have to because I’m passing
on to a rather fragile web service.

Don’t bother. Use your arguments, assuming they are the correct type.
If they are not, then a runtime exception will be thrown.

Yes and No.

If the bug is on the backtrace, this works fine. An exception is
thrown, the backtrace is printed, and you inspect each one and you
find the wrong code, and fix it.

End of story.

If however you are doing, as is quite often done, constructing an
object, passing in some of the instance variables as parameters to the
constructor…

The use that triggers the exception, is quite likely not to have the
buggy line on the backtrace. The buggy line was on the call graph
heading towards the constructor, not the use of that instance.

The duck’s backside is not watertight, the duck sinks.

Hence my static_type_check set of utilities…

So in…

class MyObject

def initialize( _a, _b, _c)
@a = _a.quacks_like( :qwaak, :waddle, :swim)
@b = _b.static_type_check String
@c = _c.polymorphic_type_check MyBaseClass
end

Without the checks above, the exceptions would be thrown here, with

the buggyline nowhere on the backtrace!
def my_use
@a.qwaak( @b) + @c
end
end

Abstract base class for all the type check exceptions

class TypeCheckException < Exception
end

This exception is thrown in event of a method being invoked with an

object of the wrong duck type.

class DuckTypingException < TypeCheckException
end

This exception is thrown in event of a method being invoked with a

parameter of of the wrong static type.

class StaticTypeException < TypeCheckException
end

This exception is thrown in event of a method being invoked with a

parameter of of the wrong polymorphic type.

class PolymorphicTypeException < TypeCheckException
end

class Object

# Raise a DuckTypingException unless the object responds to all 

symbol.
def quacks_like( *symbols)
symbols.each do |symbol|
raise DuckTypingException, “Duck typing error, expected this
object to respond to :#{symbol}, but found class
#{self.class}\n\t\t#{symbol.inspect}” unless
respond_to? symbol
end
end

def static_type_check_boolean
   raise StaticTypeException, "Static type check error, expected 

object to be a boolean, found ‘#{self.class}’
\t\t#{self.inspect}" unless
(self.class == TrueClass) ||
(self.class == FalseClass) ||
(self.class == NilClass)
self
end

def static_type_check( klass)
   raise StaticTypeException, "Static type check error, expected 

object to be exactly class ‘#{klass}’, found
‘#{self.class}’\n\t\t#{self.inspect}" unless
self.class == klass
self
end

def static_type_check_each( klass)
   each do |object|
      object.static_type_check klass
   end
   self
end

def polymorphic_type_check_each( klass)
   each do |object|
      object.polymorphic_type_check klass
   end
   self
end

def polymorphic_type_check( klass)
   #    @@static_caller[caller[1]]+=1
   raise PolymorphicTypeException, "Polymorphic type check error, 

expected object to be a kind of ‘#{klass}’, found
‘#{self.class}’\n\t\t#{self.inspect}" unless
self.kind_of? klass
self
end

end

John C. Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : [email protected]
New Zealand

On Wednesday 28 May 2008 16:25:15 John C. wrote:

# Raise a DuckTypingException unless the object responds to all symbol.
def quacks_like( *symbols)
   symbols.each do |symbol|
      raise DuckTypingException, "Duck typing error, expected this 

object to respond to :#{symbol}, but found class
#{self.class}\n\t\t#{symbol.inspect}" unless

         respond_to? symbol
   end
end

Just occurred to me that this does have one flaw: It cannot check for
what
happens when method_missing is hit. I doubt that’s much of a problem in
practice, though.

On May 28, 2008, at 1:44 PM, David M. wrote:

The only point of using Ruby (or any other tool in the universe) is
to
get a job done. :slight_smile: I would never use a Ruby feature just because Ruby
makes it possible.

Put it this way: What’s the point of using, say, Erlang, if you
never use its
concurrency features?

All I can do is repeat what I said: the ONLY point to ANYthing (in
programming) is as a means to accomplish some purpose. If using Erlang
accomplishes a given purpose best, then it should be used, no matter
what its concurrency capabilities. One reason might simply be that a
given programmer is more comfortable in that language than another,
and can therefore accomplish the task faster.

Granted, Ruby has a bit more going for it, but a lot of the joy of
using Ruby
is how much less work you end up having to do when you don’t have to
think
about types too much.

I think you mean “classes,” not “types.” At any rate, I don’t see how
Numeric === v involves more work than the alternative, so I don’t
think that criterion applies here.

No, it says “v is of class Numeric.” It’s very explicit, and makes the
assumption that anything which acts like a number will eventually
inherit
from Numeric.

Well, the desired goal is in fact to recognize objects that are
numeric. One of the purposes of classes in OOP is to categorize things.

I don’t even know what the ability to respond to :to_int means.

I think it would be :to_i, actually… And I’d probably just call
foo.to_i,
rather than testing for the existence of to_i.

:to_i is actually rather different, as it will convert a string (even
a non-numeric string like “2a”). That’s an example of having to know
the implementation of the method to determine whether testing
responds_to? makes sense. For all I know, :to_i may in fact be the
desired method, but Elizabeth used :to_int, and I assume it was for a
reason.

Remember the above – I could actually completely redefine Array, or
Numeric,
etc. So even your assumption that “Numeric === foo” tests for
Numeric is
really only based on convention – you’re assuming that no one,
anywhere in
your code, is doing stuff like this:

Numeric = nil

That’s not merely being unconventional–that’s insanity. :slight_smile: Anyway, it
applies even more so to methods, which aren’t in the global namespace.

(think Cowboy#draw and Artist#draw).

Yes, that is a downside of duck typing, as currently implemented,
but doesn’t
really apply to :to_i.

Also, context matters. If Cowboy and Artist are both in a GUI widget
library,
that Cowboy is asking for trouble.

That’s true, but it wasn’t my point. The question is whether all
methods with the same name in all active classes should be
semantically equivalent. I think that’s a rather larger assumption
than that Numeric means “numeric.”

///ark

On Thu, 29 May 2008, David M. wrote:

I’m fine with that, because 99% of the time, I’ll never hit that exception.
When I do, it’s usually possible to deal with it – in this case, you would
find where @a is set, and add a check there.

I think you’re arguing to add that check first. I would call that premature
strictness – but if you have to do it, I like your way.

Depends on what I’m doing. If I’m just doing bog standard coding, I’ll
probably skip the checks.

If I’m doing something wildly experimental, or ripping up and
restructuring a large chunk of code, I’ll probably splash checks
around with a heavy hand.

Gives me a quick heads up that I’m being stupid. Forces me to think a
little, "what do I really want coming it here? I Dunno really, but it
must quack like this. "

Run the unit test, ooh looky, I’m getting something that doesn’t quack
like that. No, no surprise now I think about it, but it holds, has, or
makes a thing that quacks like that. A quick fix in the editor and off
I go again.

John C. Phone : (64)(3) 358 6639
Tait Electronics Fax : (64)(3) 359 4632
PO Box 1645 Christchurch Email : [email protected]
New Zealand

On May 28, 2008, at 6:25 PM, David M. wrote:

I think your use case had something to do with a fragile web
service, so this
actually could make a lot of sense to you – it might even be worth
checking
if it’s an Integer.

Wasn’t my use case. :slight_smile:

///ark

On Wednesday 28 May 2008 17:23:30 Mark W. wrote:

given programmer is more comfortable in that language than another,
and can therefore accomplish the task faster.

Even if the problem doesn’t require concurrency, the main reason for
choosing
Erlang in the first place is its threading model. If you don’t like
Erlang’s
threading, chances are, the rest of it is done better in other
languages.

I’m not saying that we don’t want you if you won’t do Ruby duck typing.
Just
saying that I consider duck typing to be a major draw to Ruby in the
first
place.

I kind of feel like you’re doing the equivalent of this:

i = 0
while(i < some_array.length)
do_something_with(some_array[i])
i += 1
end

Yes, Ruby can do that, but I think most of us agree that a major appeal
of
Ruby is being able to do this instead:

some_array.each { |item|
do_something_with item
}

No, it says “v is of class Numeric.” It’s very explicit, and makes the
assumption that anything which acts like a number will eventually
inherit
from Numeric.

Well, the desired goal is in fact to recognize objects that are
numeric. One of the purposes of classes in OOP is to categorize things.

Given single inheritance, you’re not going to force everything into the
exact
category it belongs. I know I implemented a class to represent DNS
serial
numbers and their associated math. It didn’t inherit from Numeric, but
it did
have to_i.

Maybe that was bad design on my part, but the point of duck typing is
that we
don’t need to care if it calls itself “Numeric”. Instead, we care that
it
acts like a Numeric – it responds_to +, -, and probably to_i and
integer?

You’ve probably heard all this before, of course.

That’s not merely being unconventional–that’s insanity. :slight_smile: Anyway, it
applies even more so to methods, which aren’t in the global namespace.

Alright, without altering the global namespace, and with very possibly a
good
excuse, I could do something like this:

class IpAddress < Integer
def to_s
# return ‘12.34.56.78’
end
end

Now, that actually won’t work without a bit of massaging – the numeric
classes don’t have constructors. And there’s already a built in IP
address
class, so this would be pointless.

But I’m not sure there’s any more reason to believe that something which
is a
Numeric (or claims to be) is going to give you the semantics you want,
than
to believe the same of something which supports to_i (or to_int, which
is
probably more correct).

That’s true, but it wasn’t my point. The question is whether all
methods with the same name in all active classes should be
semantically equivalent. I think that’s a rather larger assumption
than that Numeric means “numeric.”

The assumption you’re making with Numeric isn’t that Numeric means
“numeric”,
but that all possibly numeric values are contained in Numeric.

I think your use case had something to do with a fragile web service, so
this
actually could make a lot of sense to you – it might even be worth
checking
if it’s an Integer.

But in the general case, I like that much of my code is actually
abstract
enough to swap something of an entirely different type (or class) in and
have
it do something useful. Recently, I actually wrote an entire class for
storing things (a two-dimensional map) without knowing what kind of
object
I’d be filling it with. I ended up filling it with Symbols.