[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Funtionality of 'case'-Expression

Ralf Müller

9/30/2004 7:24:00 AM

Salve!

Is it possible in the 'when'-part to access components or mthods of an
object specified in after 'case' ?

Something like:

case object
when object.method == 'whatever' then ...
when ohject.id%2 == 0 then ...
end

regards
ralf

14 Answers

Robert Klemme

9/30/2004 7:49:00 AM

0


"Ralf Müller" <r_mueller@imp-ag.de> schrieb im Newsbeitrag
news:2s1qktF1cjkj8U1@uni-berlin.de...
> Salve!
>
> Is it possible in the 'when'-part to access components or mthods of an
> object specified in after 'case' ?
>
> Something like:
>
> case object
> when object.method == 'whatever' then ...
> when ohject.id%2 == 0 then ...
> end

You can do

case
when object.method == 'whatever' then ...
when ohject.id%2 == 0 then ...
end

Note the subtle difference. :-)

Alternatively you can define a criterion like this:

crit1 = lambda {|x| x.method == 'whatever'}
class <<crit1; alias :=== :call end

case object
when crit1; ...
when crit2; ...
end

Kind regards

robert

Ralf Müller

9/30/2004 8:11:00 AM

0

Robert Klemme wrote:
> "Ralf Müller" <r_mueller@imp-ag.de> schrieb im Newsbeitrag
> news:2s1qktF1cjkj8U1@uni-berlin.de...
>
>>Salve!
>>
>>Is it possible in the 'when'-part to access components or mthods of an
>>object specified in after 'case' ?
>>
>>Something like:
>>
>>case object
>> when object.method == 'whatever' then ...
>> when ohject.id%2 == 0 then ...
>>end
>
>
> You can do
>
> case
> when object.method == 'whatever' then ...
> when ohject.id%2 == 0 then ...
> end
>
> Note the subtle difference. :-)
>
> Alternatively you can define a criterion like this:
>
> crit1 = lambda {|x| x.method == 'whatever'}
> class <<crit1; alias :=== :call end
>
> case object
> when crit1; ...
> when crit2; ...
> end
>
> Kind regards
>
> robert
>
thanks robert,
this lambda mechanism is an interessting point.
What you do, is an in-place-extension of 'class' only for its actual
instance 'object', right? And you call it '===', because 'case' needs
this functcion.
But whitch alias do you choose for 'crit2?

ralf

--------------------------------------------------------------------
Ceterum censeo cartaginem esse dilendam.

gabriele renzi

9/30/2004 8:49:00 AM

0

Ralf Müller ha scritto:

> thanks robert,
> this lambda mechanism is an interessting point.
> What you do, is an in-place-extension of 'class' only for its actual
> instance 'object', right?

He's adding that method to the singleton class of 'crit1'.
actually I prefer:

def crit2.===(z) call ; end
this may be of interest to you:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-t...
It explains singleton classes in a lovely way :)

> And you call it '===', because 'case' needs
> this functcion.
> But whitch alias do you choose for 'crit2?
>

crit2 = lambda {|x| x.id == 'whatever'}
def crit2.===(z) call ; end

but /I/ prefer:

Brian Candler

9/30/2004 11:39:00 AM

0

On Thu, Sep 30, 2004 at 04:25:03PM +0900, Ralf M?ller wrote:
> Is it possible in the 'when'-part to access components or mthods of an
> object specified in after 'case' ?
>
> Something like:
>
> case object
> when object.method == 'whatever' then ...
> when ohject.id%2 == 0 then ...
> end

How about:

def with(obj,&blk) obj.instance_eval(&blk); end

...

with(object) do
if method == 'whatever' then ...
elsif id%2 == 0 then ...
end
end

Regards,

Brian.


Mark Hubbart

9/30/2004 6:41:00 PM

0

On Thu, 30 Sep 2004 16:50:03 +0900, Robert Klemme <bob.news@gmx.net> wrote:
>
> "Ralf Müller" <r_mueller@imp-ag.de> schrieb im Newsbeitrag
> news:2s1qktF1cjkj8U1@uni-berlin.de...
>
>
> > Salve!
> >
> > Is it possible in the 'when'-part to access components or mthods of an
> > object specified in after 'case' ?
> >
> > Something like:
> >
> > case object
> > when object.method == 'whatever' then ...
> > when ohject.id%2 == 0 then ...
> > end
>
> You can do
>
> case
> when object.method == 'whatever' then ...
> when ohject.id%2 == 0 then ...
> end
>
> Note the subtle difference. :-)
>
> Alternatively you can define a criterion like this:
>
> crit1 = lambda {|x| x.method == 'whatever'}
> class <<crit1; alias :=== :call end
>
> case object
> when crit1; ...
> when crit2; ...
> end

This sounds like a use case for the Proc.new extension proposal in the
latest ruby-dev summary... To quote:

> Nowake proposed that a Proc object should be invoked with
> any method name like that:
>
>       m = Proc.new( :to_s ) { 'test1' }
>       p m.to_s   # => 'test1'

So your code could be:
crit1 = Proc.new(:===){|x| x.method === 'whatever'}
case object
when crit1
end

Hmmm... I didn't like the idea before, but I might be changing my mind.

cheers,
Mark

>
> Kind regards
>
> robert
>
>



Brian Candler

9/30/2004 7:13:00 PM

0

> > You can do
> >
> > case
> > when object.method == 'whatever' then ...
> > when ohject.id%2 == 0 then ...
> > end
...
> This sounds like a use case for the Proc.new extension proposal in the
> latest ruby-dev summary...
...
> So your code could be:
> crit1 = Proc.new(:===){|x| x.method === 'whatever'}
> case object
> when crit1
> end
...
> Hmmm... I didn't like the idea before, but I might be changing my mind.

Let's factor out the variable, so we get

case object
when Proc.new(:===){|x| x.method == 'whatever' }
... do stuff1
when Proc.new(:===){|x| x.id%2 == 0 }
... do stuff2
end

Now, how about I write instead:

if object.method == 'whatever'
... do stuff1
elsif object.id%2 == 0
... do stuff2
end

Well, I know which one I'd prefer to read or write :-)

If the underlying objective is just to factor out the common 'object.' in
each branch, then I'd still suggest

object.instance_eval {
case
when method == 'whatever'
... do stuff1
when id%2 == 0
.. do stuff2
end
}

Regards,

Brian.


Markus

9/30/2004 7:36:00 PM

0

On Thu, 2004-09-30 at 12:13, Brian Candler wrote:
> > > You can do
> > >
> > > case
> > > when object.method == 'whatever' then ...
> > > when ohject.id%2 == 0 then ...
> > > end
> ...
> > This sounds like a use case for the Proc.new extension proposal in the
> > latest ruby-dev summary...
> ...
> > So your code could be:
> > crit1 = Proc.new(:===){|x| x.method === 'whatever'}
> > case object
> > when crit1
> > end
> ...
> Let's factor out the variable, so we get
>
> case object
> when Proc.new(:===){|x| x.method == 'whatever' }
> ... do stuff1
> when Proc.new(:===){|x| x.id%2 == 0 }
> ... do stuff2
> end

But "factoring out the variable" largely misses the point. Try it
with a concrete example:

def criterion(&b)
Proc.new :===,&b
end


non_numeric = criterion {|x| !(x.is_a? Numeric}
negative = criterion {|x| x < 0}
prime = criterion {|x| ...
case n
when non_numeric ...
when negative ...
when Float ...
when prime ...
else ...
end

This could lead to much more readable code in some circumstances. Also,
note how easily criteria could be passed around, shared or predicated,
etc.

-- Markus






Brian Candler

9/30/2004 8:13:00 PM

0

> But "factoring out the variable" largely misses the point. Try it
> with a concrete example:
>
> def criterion(&b)
> Proc.new :===,&b
> end
>
>
> non_numeric = criterion {|x| !(x.is_a? Numeric}
> negative = criterion {|x| x < 0}
> prime = criterion {|x| ...
> case n
> when non_numeric ...
> when negative ...
> when Float ...
> when prime ...
> else ...
> end

Fair enough. I'd make those criteria constants, rather than local variables
- perhaps in all-caps to avoid confusion with classes like Float.

However, I notice you decided to wrap Proc.new(:sym) in a method - which
suggests to me that there is little benefit from having the new feature in
Proc.new, as your 'criterion' method could just as well have done the work
there.

Perhaps it makes more sense in this particular example to subclass Proc,
giving a "Proc which has an === method for use in case statements":

class Criterion < Proc
def ===(other)
call(other)
end
end
NEGATIVE = Criterion.new {|x| x < 0 }

[1,3,-4].each do |v|
puts v
case v
when NEGATIVE
puts "Negative!"
end
end

Regards,

Brian.


Brian Candler

9/30/2004 9:13:00 PM

0

On Fri, Oct 01, 2004 at 05:13:24AM +0900, Brian Candler wrote:
> Perhaps it makes more sense in this particular example to subclass Proc,
> giving a "Proc which has an === method for use in case statements":

Or arguably, just alias Proc#=== to Proc#call in the language core for use
in case statements, in the same way as Class#=== exists primary for use in
case statements.

It's interesting to observe that these objects we're talking about are the
same as the selector blocks you'd use in Array#find and friends.

Regards,

Brian.


Markus

10/1/2004 12:40:00 AM

0

On Thu, 2004-09-30 at 13:13, Brian Candler wrote:
> > But "factoring out the variable" largely misses the point. Try it
> > with a concrete example:
> >
> > def criterion(&b)
> > Proc.new :===,&b
> > end

> Perhaps it makes more sense in this particular example to subclass Proc,
> giving a "Proc which has an === method for use in case statements":
>
> class Criterion < Proc
> def ===(other)
> call(other)
> end
> end
> NEGATIVE = Criterion.new {|x| x < 0 }

*smile* I'd be more enthusiastic about that if I hadn't just been
burned subclassing Proc (my whole "some Proc objects quietly exploding a
single argument if it happens to be an array bug" rant).

> Fair enough. I'd make those criteria constants, rather than local variables
> - perhaps in all-caps to avoid confusion with classes like Float.

What's wrong with them being variables? They are first class
citizen, after all. We can pass them around, change their value
(imagine instead of "negative" and "prime" criteria like
"acceptable_to_most_voters" or "not_too_ugly" that may have
(complicated) values constructed elsewhere) and in general do anything
we want with the values.
So why artificially constrain their "storage class"?

-- MarkusQ