# Complex type-checking

**URL:** <https://www.ruby-forum.com/t/complex-type-checking/183868>\
**Category:** Ruby\
**Created:** [February 22, 2010, 4:43am UTC](https://www.ruby-forum.com/t/complex-type-checking/183868 "2010-02-22T04:43:17Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![lqqkout4elfy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/ebca7d/32.png) [@lqqkout4elfy](https://www.ruby-forum.com/u/lqqkout4elfy)\
**Post date:** [February 22, 2010, 4:43am UTC](https://www.ruby-forum.com/t/complex-type-checking/183868/1 "2010-02-22T04:43:17Z")

</div>

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!

---

<div class="post-metadata">

**Author:** ![lqqkout4elfy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/ebca7d/32.png) [@lqqkout4elfy](https://www.ruby-forum.com/u/lqqkout4elfy)\
**Post date:** [February 22, 2010, 9:59am UTC](https://www.ruby-forum.com/t/complex-type-checking/183868/2 "2010-02-22T09:59:22Z")

</div>

2010/2/22 Ken C. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

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

Sorry, I can’t. Why do you want to do that? 🙂

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

Is it?

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.

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

Provide different methods for different arguments.

Kind regards

robert

---

<div class="post-metadata">

**Author:** ![lqqkout4elfy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/ebca7d/32.png) [@lqqkout4elfy](https://www.ruby-forum.com/u/lqqkout4elfy)\
**Post date:** [February 22, 2010, 10:38am UTC](https://www.ruby-forum.com/t/complex-type-checking/183868/3 "2010-02-22T10:38:32Z")

</div>

Robert K. wrote:

> > So 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? 🙂

🙂

> > Which is actually turning out to be a right bugger to code, actually.
> 
> 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-)}

---

<div class="post-metadata">

**Author:** ![lqqkout4elfy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/ebca7d/32.png) [@lqqkout4elfy](https://www.ruby-forum.com/u/lqqkout4elfy)\
**Post date:** [February 22, 2010, 5:06pm UTC](https://www.ruby-forum.com/t/complex-type-checking/183868/4 "2010-02-22T17:06:51Z")

</div>

Thomas S. wrote:

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

---

<div class="post-metadata">

**Author:** ![lqqkout4elfy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/ebca7d/32.png) [@lqqkout4elfy](https://www.ruby-forum.com/u/lqqkout4elfy)\
**Post date:** [February 22, 2010, 1:29pm UTC](https://www.ruby-forum.com/t/complex-type-checking/183868/5 "2010-02-22T13:29:31Z")

</div>

On Feb 21, 10:43 pm, Ken C. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

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

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