[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

comparison operations in case statements

Joel VanderWerf

1/14/2006 8:00:00 PM


This looks kind of cute, as a way to mix class-matching tests with
comparison operator tests in case statements. Too bad it's not really
practical (the commented out caching may help a bit, but may also use
too much memory):

class Comparator < Proc
def ===(val)
call val
end

def &(other)
compare do |val|
self[val] and other[val]
end
end
end

def compare
Comparator.new
end

class Numeric
#@comparator_lt = {}
def self.<(x)
#@comparator_lt[x] ||=
compare do |val|
self === val and val < x
end
end

#@comparator_gt = {}
def self.>(x)
#@comparator_gt[x] ||=
compare do |val|
self === val and val > x
end
end
end


raise unless (Numeric < 6) === 3
raise if (Integer < 6) === 2.3
raise if (Integer < 6) === "foo"

case 3
when (Numeric < 6) & (Numeric > 5); raise
when (Numeric < 0) & (Numeric > -10); raise
when (Numeric < 6) & (Numeric > 2)
else raise
end

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407


2 Answers

Logan Capaldo

1/14/2006 9:17:00 PM

0


On Jan 14, 2006, at 3:00 PM, Joel VanderWerf wrote:

>
> This looks kind of cute, as a way to mix class-matching tests with
> comparison operator tests in case statements. Too bad it's not really
> practical (the commented out caching may help a bit, but may also use
> too much memory):
>
> class Comparator < Proc
> def ===(val)
> call val
> end
>
> def &(other)
> compare do |val|
> self[val] and other[val]
> end
> end
> end
>
> def compare
> Comparator.new
> end
>
> class Numeric
> #@comparator_lt = {}
> def self.<(x)
> #@comparator_lt[x] ||=
> compare do |val|
> self === val and val < x
> end
> end
>
> #@comparator_gt = {}
> def self.>(x)
> #@comparator_gt[x] ||=
> compare do |val|
> self === val and val > x
> end
> end
> end
>
>
> raise unless (Numeric < 6) === 3
> raise if (Integer < 6) === 2.3
> raise if (Integer < 6) === "foo"
>
> case 3
> when (Numeric < 6) & (Numeric > 5); raise
> when (Numeric < 0) & (Numeric > -10); raise
> when (Numeric < 6) & (Numeric > 2)
> else raise
> end
>
> --
> vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407
>

Neat. Seems a little redundant though

raise unless Numeric === 3
case
when 3 < 6 and 3 > 5; raise
when 3 < 0 and 3 > -10; raise
when 3 < 6 and 3 > 2
else raise
end

I'm presuming nine times out of ten the variable you'll run these
tests on will have less characters than Numeric for instance.

eg:
x = 3
raise unless Numeric === x
case
when x > 2; ...
end




Robert Klemme

1/14/2006 11:31:00 PM

0

Joel VanderWerf <vjoel@path.berkeley.edu> wrote:
> This looks kind of cute, as a way to mix class-matching tests with
> comparison operator tests in case statements. Too bad it's not really
> practical (the commented out caching may help a bit, but may also use
> too much memory):
>
> class Comparator < Proc
> def ===(val)
> call val
> end
>
> def &(other)
> compare do |val|
> self[val] and other[val]
> end
> end
> end

This doesn't allow for arbitrary chaining. You would rather have to return
something that overloads & as well. But that will be difficult in the light
of the last value returned (you don't know that it's the last value in the
method).

> def compare
> Comparator.new
> end
>
> class Numeric
> #@comparator_lt = {}
> def self.<(x)
> #@comparator_lt[x] ||=
> compare do |val|
> self === val and val < x
> end
> end
>
> #@comparator_gt = {}
> def self.>(x)
> #@comparator_gt[x] ||=
> compare do |val|
> self === val and val > x
> end
> end
> end
>
>
> raise unless (Numeric < 6) === 3
> raise if (Integer < 6) === 2.3
> raise if (Integer < 6) === "foo"
>
> case 3
> when (Numeric < 6) & (Numeric > 5); raise
> when (Numeric < 0) & (Numeric > -10); raise
> when (Numeric < 6) & (Numeric > 2)
> else raise
> end

I'd prefer the more general approach as I suggested a while back already:

module Kernel
private
condition(&cond)
class<<cond
alias :=== :call
end
cond
end
end

Then you can do

case 3
when condition {|x| x<6 && x>5}; ...

end

or

LESS_THAN_6_AND_GREATER_THAN_5 = condition {|x| x<6 && x>5}

case 3
when LESS_THAN_6_AND_GREATER_THAN_5; ...
....

or better

ILLEGAL = condition {|x| x<6 && x>5 or ...}

case x
when ILLEGAL; raise ...
....

Of course this looks silly in this case, but in more reasonable cases it
doesn't. For example

NEGATIVE = condition {|x|x<0}
EVEN = condition {|x| x%2==0}

case x
when NEGATIVE; raise "error!"
when EVEN; puts "found an even number"
end

which reads nicely.

Kind regards

robert