Complex type-checking

K

Ken Coar

I have a number of methods that can take arguments in two different
forms. As an example:

method(tuple [, ...])

where 'tuple' can be things like (Point, Point, Integer) or (Numeric,
Numeric, Numeric, Numeric, Integer) (so either a Point object
representing the coordinates, or the coordinates directly).

I realise that type-checking in Ruby is anathematic to some, but I want
to generate some intelligent error messages in some cases. So please
let's leave the 'why do you want to do that' bit alone for now. :)

One meta-thought I had was for the argument vetter to be passed the
arglist and an array of allowed patterns, like

[
%r/^(?:(?:point\s*){2}\s*Integer)+$/,
%r/^(?:(?:Numeric\s*){4}\s*Integer)+$/
]

and check each tuple by doing kind_of?() of each element against the
appropriate words in the pattern.

Which is actually turning out to be a right bugger to code, actually.

So I'm figuring maybe someone could suggest a better method to me?

Thanks!
 
R

Robert Klemme

2010/2/22 Ken Coar said:
I have a number of methods that can take arguments in two different
forms. =A0As an example:

method(tuple [, ...])

where 'tuple' can be things like (Point, Point, Integer) or (Numeric,
Numeric, Numeric, Numeric, Integer) (so either a Point object
representing the coordinates, or the coordinates directly).

I realise that type-checking in Ruby is anathematic to some, but I want
to generate some intelligent error messages in some cases. =A0So please
let's leave the 'why do you want to do that' bit alone for now. :)

Sorry, I can't. Why do you want to do that? :)
One meta-thought I had was for the argument vetter to be passed the
arglist and an array of allowed patterns, like

[
=A0%r/^(?:(?:point\s*){2}\s*Integer)+$/,
=A0%r/^(?:(?:Numeric\s*){4}\s*Integer)+$/
]

and check each tuple by doing kind_of?() of each element against the
appropriate words in the pattern.

Which is actually turning out to be a right bugger to code, actually.

Is it?

def pattern_check(args, pattern)
m =3D pattern.match(args.map{|x|x.class}.join(' '))

if m
m.to_a.each_with_index do |m,i|
return i if i > 0 && m
end
end

raise ArgumentError, args.inspect
end

def m(*a)
case pattern_check(a, %r{\A(?:(String String)|(Fixnum))\z})
when 1
printf "Two strings: %p\n", a
when 2
printf "A number: %p\n", a
else
raise ArgumentError, a.inspect
end
end

Method m does look ugly though.
So I'm figuring maybe someone could suggest a better method to me?

Provide different methods for different arguments.

Kind regards

robert


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

Ken Coar

Robert said:
Sorry, I can't. Why do you want to do that? :)
:)


Is it?

Well, it seems to be..

The thing is, the Point class match works all right -- but when
specified as individual coordinates, they can be integers (potentially
bignums) or floats -- so checking the actual coordinates is not as
simple as matching the class. I *could* do a (Fixnum|Float|...)
alternation, I suppose, but that doesn't extend to cases in which
someone might be using a custom class extending one of those. Which is
actually probably a bit unlikely, so maybe I'll just rule that
possibility out. :)
def pattern_check(args, pattern)
m = pattern.match(args.map{|x|x.class}.join(' '))

if m
m.to_a.each_with_index do |m,i|
return i if i > 0 && m
end
end

raise ArgumentError, args.inspect
end

def m(*a)
case pattern_check(a, %r{\A(?:(String String)|(Fixnum))\z})
when 1
printf "Two strings: %p\n", a
when 2
printf "A number: %p\n", a
else
raise ArgumentError, a.inspect
end
end

Method m does look ugly though.

Consider also that the argument list may include more than one tuple..

This has given me some ideas, though. Thanks!

#ken B-)}
 
I

Intransition

I have a number of methods that can take arguments in two different
forms. =A0As an example:

method(tuple [, ...])

where 'tuple' can be things like (Point, Point, Integer) or (Numeric,
Numeric, Numeric, Numeric, Integer) (so either a Point object
representing the coordinates, or the coordinates directly).

I realise that type-checking in Ruby is anathematic to some, but I want
to generate some intelligent error messages in some cases. =A0So please
let's leave the 'why do you want to do that' bit alone for now. :)

Let the error happen then wrap the call in a begin/rescue clause and
give more intelligent error messages based on the return error.
 
K

Ken Coar

Thomas said:
Let the error happen then wrap the call in a begin/rescue clause and
give more intelligent error messages based on the return error.

.. which would require lots of extra code to account for all
possibilities. Better to vet the arguments to begin with rather than to
try to recover when they fail somewhere farther down the code, IMHO.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top