Ruby's "case" doesn't behave like a normal switch

The problem with ruby is that you can't use a switch as it behaves with many
other languages like C, php, etc.

For example, you want to convert the following peace of code to ruby:

switch (x) {
  case 1:
  case 2:
    # do something
    break;
  case 3:
    # do some other thing
    break;
  default:
}

it seems you can do it with the following code:

case x
  when 1..2
    # do something
  when 3
    # do some other thing
  else
end

But when it comes to strings, you would like to be able to do simply:

case x
  when "this"
  when "that"
    # do something common to "this" and "that"
  when "nothing"
    # something different
end

The problem is that you can't, because of the fact the "break" is implicit
in
the ruby language.
The fact is that you don't want to rewrite the same code two times.
Of course, you would be able to right your code into a function, and then
just
write:

case x
  when "this"
    func_this_that()
  when "that"
    func_this_that()
  when "nothing"
    # something different
end

But if again, you don't want to relay on a function call, here's a solution
I thought about.

This is not perfect, because you have to change your syntax, but it might be
quite useful in some cases.

# Redefine the === method of the Array class, that is used to match the
argument
# of the "case" directive.
class Array
  # Return true if self contains any element of the given parameter.
  def ===(o)
    o.each do |e|
      return true if self.include?(e)
    end
    false
  end
end

# Example 1
x = ["case4"]

case x
  when ["case1", "case2"]
    puts "first case"
  when ["case3", "case4", "case5"]
    puts "second case"
  when ["case6"]
    puts "third case"
  else
    puts "not matched"
end

# Returns: "second case"

# Example 2
x = [6]

case x
  when [1, 2]
    puts "first case"
  when [3, 4, 5]
    puts "second case"
  when [6]
    puts "third case"
  else
    puts "not matched"
end

# Returns: "third case"

What do you think about it ?

Hi,

···

On Fri, Feb 23, 2007 at 10:55:06AM +0900, Guillaume Nargeot wrote:

The fact is that you don't want to rewrite the same code two times.
Of course, you would be able to right your code into a function, and then
just
write:

case x
  when "this"
    func_this_that()
  when "that"
    func_this_that()
  when "nothing"
    # something different
end

case x
  when "this", "that"
    func_this_that()
  when "nothing"
    # something different
end

--
eban

Check this out for making your case statements work:

http://redhanded.hobix.com/bits/wonderOfTheWhenBeFlat.html

"Consider Olympic ice dancing out-graced!"

-kjell

···

On Feb 22, 2007, at 7:55 PM, Guillaume Nargeot wrote:

The problem with ruby is that you can't use a switch as it behaves with many
other languages like C, php, etc.

For example, you want to convert the following peace of code to ruby:

switch (x) {
  case 1:
  case 2:
    # do something
    break;
  case 3:
    # do some other thing
    break;
  default:
}

it seems you can do it with the following code:

case x
  when 1..2
    # do something
  when 3
    # do some other thing
  else
end

But when it comes to strings, you would like to be able to do simply:

case x
  when "this"
  when "that"
    # do something common to "this" and "that"
  when "nothing"
    # something different
end

The problem is that you can't, because of the fact the "break" is implicit
in
the ruby language.
The fact is that you don't want to rewrite the same code two times.
Of course, you would be able to right your code into a function, and then
just
write:

case x
  when "this"
    func_this_that()
  when "that"
    func_this_that()
  when "nothing"
    # something different
end

But if again, you don't want to relay on a function call, here's a solution
I thought about.

This is not perfect, because you have to change your syntax, but it might be
quite useful in some cases.

# Redefine the === method of the Array class, that is used to match the
argument
# of the "case" directive.
class Array
  # Return true if self contains any element of the given parameter.
  def ===(o)
    o.each do |e|
      return true if self.include?(e)
    end
    false
  end
end

# Example 1
x = ["case4"]

case x
  when ["case1", "case2"]
    puts "first case"
  when ["case3", "case4", "case5"]
    puts "second case"
  when ["case6"]
    puts "third case"
  else
    puts "not matched"
end

# Returns: "second case"

# Example 2
x = [6]

case x
  when [1, 2]
    puts "first case"
  when [3, 4, 5]
    puts "second case"
  when [6]
    puts "third case"
  else
    puts "not matched"
end

# Returns: "third case"

What do you think about it ?

These two examples are not equivalent. In one, you're listing multiple
cases on a single line with the associated code following it. In the
other, you're listing cases separately and letting the lack of a break
cause it to fail over to the next -- which leads to a very unintuitive
set of code. Why not just employ your list of cases for the same
resulting code on one line? That works just fine.

···

On Fri, Feb 23, 2007 at 10:55:06AM +0900, Guillaume Nargeot wrote:

it seems you can do it with the following code:

case x
  when 1..2
    # do something
  when 3
    # do some other thing
  else
end

But when it comes to strings, you would like to be able to do simply:

case x
  when "this"
  when "that"
    # do something common to "this" and "that"
  when "nothing"
    # something different
end

--
CCD CopyWrite Chad Perrin [ http://ccd.apotheon.org ]
"The ability to quote is a serviceable
substitute for wit." - W. Somerset Maugham

Hi --

The problem with ruby is that you can't use a switch as it behaves with many
other languages like C, php, etc.

I don't consider that a problem. If all languages had to behave
exactly the same way, there would only be one language, and we'd all
get bored :slight_smile:

This is not perfect, because you have to change your syntax, but it might be
quite useful in some cases.

# Redefine the === method of the Array class, that is used to match the
argument
# of the "case" directive.
class Array
# Return true if self contains any element of the given parameter.
def ===(o)
   o.each do |e|
     return true if self.include?(e)
   end
   false
end
end

# Example 1
x = ["case4"]

case x
when ["case1", "case2"]
   puts "first case"
when ["case3", "case4", "case5"]
   puts "second case"
when ["case6"]
   puts "third case"
else
   puts "not matched"
end

# Returns: "second case"

# Example 2
x = [6]

case x
when [1, 2]
   puts "first case"
when [3, 4, 5]
   puts "second case"
when [6]
   puts "third case"
else
   puts "not matched"
end

# Returns: "third case"

What do you think about it ?

It's very dangerous. Remember that changing Array#=== changes it
everywhere. There may be places in Ruby itself, or in other libraries
you're using, that depend on the original behavior.

David

···

On Fri, 23 Feb 2007, Guillaume Nargeot wrote:

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black\)
    (See what readers are saying! http://www.rubypal.com/r4rrevs.pdf\)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)

Guillaume Nargeot wrote:

# Example 1
x = ["case4"]

case x
  when ["case1", "case2"]
    puts "first case"
  when ["case3", "case4", "case5"]
    puts "second case"
  when ["case6"]
    puts "third case"
  else
    puts "not matched"
end

# Returns: "second case"

# Example 2
x = [6]

case x
  when [1, 2]
    puts "first case"
  when [3, 4, 5]
    puts "second case"
  when [6]
    puts "third case"
  else
    puts "not matched"
end

# Returns: "third case"

What do you think about it ?
  

You can already do this:

a = [3, 4, 5]
case x
  when 1, 2
    puts "first case"
  when *a
    puts "second case"
  when 6
    puts "third case"
  else
    puts "not matched"
end

There are cases of C's fall-through switch, that cannot be emulated by Ruby's case - and I think that's a good thing. To make breaks necessary to break out of a case clause (and creating the danger for programmers to incidentally forget one), was probably one of the most inane ideas of the C language's creators.

···

--
Florian Frank

For completeness sake, you can also emulate C's lack of a break;
statement in ruby by doing redo/retry, like:

a = 1

catch(:redo) do
  case a
  when 1
    print '1'
    a = 2
    redo
  when 2
    puts 'and 2'
  end
end

This makes ruby's case statement probably the best of any language.

···

On 22 Feb., 22:54, Guillaume Nargeot <guillaume.nargeotDONOTFUCKINGS...@fusionsystems.co.jp> wrote:

The problem with ruby is that you can't use a switch as it behaves with many
other languages like C, php, etc.

For example, you want to convert the following peace of code to ruby:

switch (x) {
  case 1:
  case 2:
    # do something
    break;
  case 3:
    # do some other thing
    break;
  default:

}

This is a long shot, but since there are many EE guys here... does anybody know if there's any effort going on for openaccess database ruby binding?

I want to try it myself, but it looks like a big task, so I thought I ask first

-andre

···

_________________________________________________________________
Refi Now: Rates near 39yr lows! $430,000 Mortgage for $1,399/mo - Calculate new payment http://www.lowermybills.com/lre/index.jsp?sourceid=lmb-9632-17727&moid=7581

case x
  when "this", "that"
    func_this_that()
  when "nothing"
    # something different
end

Thank you very much !!!
I thought I tested everything, but obviously not this one.
I didn't even find anything about it in the official documentation.

So, thank you again, that is exactely what I needed :wink:

There are cases of C's fall-through switch, that cannot be emulated by
Ruby's case - and I think that's a good thing. To make breaks necessary
to break out of a case clause (and creating the danger for programmers
to incidentally forget one), was probably one of the most inane ideas of
the C language's creators.

Yeah -- this is a feature which you might not recognize as such
because you're used to the bug.

···

--
Giles Bowkett
http://www.gilesgoatboy.org

http://gilesgoatboy.blogspot.com

gga schrieb:

For completeness sake, you can also emulate C's lack of a break;
statement in ruby by doing redo/retry, like:

a = 1

catch(:redo) do
  case a
  when 1
    print '1'
    a = 2
    redo
  when 2
    puts 'and 2'
  end
end

This makes ruby's case statement probably the best of any language.

I didn't know the "catch(:redo)". Is this documented somewhere?

Regards,
Pit

http://www.rubycentral.com/book/tut_expressions.html
Search down to the section headed "Case Expressions"

···

On Fri, Feb 23, 2007 at 02:05:10PM +0900, Guillaume Nargeot wrote:

> case x
> when "this", "that"
> func_this_that()
> when "nothing"
> # something different
> end

Thank you very much !!!
I thought I tested everything, but obviously not this one.
I didn't even find anything about it in the official documentation.

It doesn't have to be catch(:redo) specifically, and in fact its use may be misleading -- here, catch is simply being used to introduce an iteration context. For example, this works just as well:

  def foo ; yield ; end

  a = 1
  foo do
    case a
    when 1
      print '1'
      a = 2
      redo
    when 2
      puts 'and 2'
    end
  end

-mental

···

On Thu, 1 Mar 2007 04:36:39 +0900, Pit Capitain <pit@capitain.de> wrote:

catch(:redo) do
  case a
  when 1
    print '1'
    a = 2
    redo
  when 2
    puts 'and 2'
  end
end

I didn't know the "catch(:redo)". Is this documented somewhere?

Well the redo is really reacting as part of the catch block (though
other block forms would do). Consider this example:

def my_iter(exp)
  yield
end

my_iterr(p(:arg)) {p :block}
#=> :arg and :ok once in order

# Caution with the following. have ^C handy

my_iter(p(:arg)) {p :before; redo; p :after}
#=> :arg once and then infinite loop of :before

my_iter(p(:arg)) {p :before; retry; p :after}
#=> :arg then :before. both repeated infinitely

Brian.

···

On 2/28/07, Pit Capitain <pit@capitain.de> wrote:

gga schrieb:
> For completeness sake, you can also emulate C's lack of a break;
> statement in ruby by doing redo/retry, like:
>
> a = 1
>
> catch(:redo) do
> case a
> when 1
> print '1'
> a = 2
> redo
> when 2
> puts 'and 2'
> end
> end
>
> This makes ruby's case statement probably the best of any language.

I didn't know the "catch(:redo)". Is this documented somewhere?

'redo' is documented at
http://www.rubycentral.com/book/tut_expressions.html

'catch' is documented at
http://www.rubycentral.com/book/tut_exceptions.html

However they're not a pair, and I don't think that 'catch' does anything in
particular in the above example, apart from causing the block to be executed
once. You could achieve the same with:

a = 1
1.times do
  case a
  when 1
    print '1'
    a = 2
    redo
  when 2
    puts 'and 2'
  end
end

Or:

a = 1
begin
  case a
  when 1
    print '1'
    a = 2
    redo
  when 2
    puts 'and 2'
  end
end while false

Regards,

Brian.

···

On Thu, Mar 01, 2007 at 04:36:39AM +0900, Pit Capitain wrote:

gga schrieb:
>For completeness sake, you can also emulate C's lack of a break;
>statement in ruby by doing redo/retry, like:
>
>a = 1
>
>catch(:redo) do
> case a
> when 1
> print '1'
> a = 2
> redo
> when 2
> puts 'and 2'
> end
>end
>
>This makes ruby's case statement probably the best of any language.

I didn't know the "catch(:redo)". Is this documented somewhere?

I didn't know about this syntax, either. Thanks, Eban ! For the Strings, I
thought about using Regex, instead :

case x
  when /this|that/
    func_this_that()
  when "nothing"
    # something different
end

···

Le vendredi 23 février 2007 11:30, Brian Candler a écrit :

On Fri, Feb 23, 2007 at 02:05:10PM +0900, Guillaume Nargeot wrote:
> > case x
> > when "this", "that"
> > func_this_that()
> > when "nothing"
> > # something different
> > end
>
> Thank you very much !!!
> I thought I tested everything, but obviously not this one.
> I didn't even find anything about it in the official documentation.

http://www.rubycentral.com/book/tut_expressions.html
Search down to the section headed "Case Expressions"

--
Olivier Renaud

MenTaLguY schrieb:

It doesn't have to be catch(:redo) specifically, and in fact its use
may be misleading -- here, catch is simply being used to introduce an
iteration context.
(...)

Ah, of course. Thanks Mental.

Regards,
Pit

That's not the same though. I think you'd need:

  when /\A(this|that)\z/

(which is a gotcha if you come from Perl, and expect to use ^...$ to match
the start and end of the string)

Regards,

Brian.

···

On Fri, Feb 23, 2007 at 10:18:34PM +0900, Olivier Renaud wrote:

Le vendredi 23 février 2007 11:30, Brian Candler a écrit :
> On Fri, Feb 23, 2007 at 02:05:10PM +0900, Guillaume Nargeot wrote:
> > > case x
> > > when "this", "that"
> > > func_this_that()
> > > when "nothing"
> > > # something different
> > > end
> >
> > Thank you very much !!!
> > I thought I tested everything, but obviously not this one.
> > I didn't even find anything about it in the official documentation.
>
> http://www.rubycentral.com/book/tut_expressions.html
> Search down to the section headed "Case Expressions"

I didn't know about this syntax, either. Thanks, Eban ! For the Strings, I
thought about using Regex, instead :

case x
  when /this|that/
    func_this_that()
  when "nothing"
    # something different
end