How to "break" a "case-when"?

Hi, is not possible to terminate the body of a "when" stament?

I mean:

  case num
  when 1:
    puts "Is 1 !!!!"
    break
    puts "Don't write it"
  end

  puts "Write it"

but unfortunatelly the "break" gives an error.

Thanks for any suggestion.

···

--
Iñaki Baz Castillo
<ibc@aliax.net>

# Hi, is not possible to terminate the body of a "when" stament?
# case num
# when 1:
# puts "Is 1 !!!!"
# break
# puts "Don't write it"
# end
# puts "Write it"

afaik, no. but why would you want to do that? are you porting c codes?

kind regards -botp

···

From: Iñaki Baz Castillo [mailto:ibc@aliax.net]

break is only for iteration. What are you trying to do?
The example you've given is not a compelling use case,
since you can simply remove the line after break.

Also, Ruby's case/when doesn't fall through when clauses.

    case 1
    when 1
      puts "it's 1"
    when 2
      puts "this is not printed"
    end

Stefan

···

2008/4/17, Iñaki Baz Castillo <ibc@aliax.net>:

Hi, is not possible to terminate the body of a "when" stament?

I mean:

  case num
  when 1:
    puts "Is 1 !!!!"
    break
    puts "Don't write it"
  end

  puts "Write it"

but unfortunatelly the "break" gives an error.

Ok, I write a better example:

  var = ...something...

case num
  when 1:
    puts "var not valid !!!!!" if ( var < 0 || var > 10 )
    break
    do_normal_stuff
    ...
    ...
    end_normal_stuff
  end

  puts "Write it"

I just want do_normal_stuff in case "var" is valid.
Yes, I can put a big "if" stament and so but I would like not to do it
since it makes a bit ugly the code.

···

2008/4/17, Stefan Lang <perfectly.normal.hacker@gmail.com>:

break is only for iteration. What are you trying to do?
The example you've given is not a compelling use case,
since you can simply remove the line after break.

--
Iñaki Baz Castillo
<ibc@aliax.net>

Iñaki Baz Castillo wrote:

break is only for iteration. What are you trying to do?
The example you've given is not a compelling use case,
since you can simply remove the line after break.
    
Ok, I write a better example:

  var = ...something...

case num
  when 1:
    puts "var not valid !!!!!" if ( var < 0 || var > 10 )
    break
    do_normal_stuff
    ...
    end_normal_stuff
  end

  puts "Write it"

I just want do_normal_stuff in case "var" is valid.
Yes, I can put a big "if" stament and so but I would like not to do it
since it makes a bit ugly the code.

But in this example the code between do_normal_stuff and end_normal_stuff would never be executed, not even in C!

Why not write something simpler

case num
when 1:
  if 0 <= var and var <= 10) then
    do_normal_stuff
    ...
    end_normal_stuff
    puts "Write it"
  end

I think you are trying to be too clever here. Stick to the simple stuff.

···

2008/4/17, Stefan Lang <perfectly.normal.hacker@gmail.com>:

Well, since Ruby doesn't support it, you must find other
ways to structure the code in each case. Exceptions might
help in the bigger picture, splitting it up in smaller methods, etc.

You can use catch/throw for this:

    catch(:invalid_var) {
      case num
      when 1
        if var < 0 || var > 10
          puts "var not valid !!!!!"
          throw(:invalid_var)
        end
        do_normal_stuff
        ...
        ...
        end_normal_stuff
      end
    }
    puts "Write it"

But be careful, catch/throw is dynamically scoped.
"ri catch" has more info.

Stefan

···

2008/4/17, Iñaki Baz Castillo <ibc@aliax.net>:

2008/4/17, Stefan Lang <perfectly.normal.hacker@gmail.com>:

> break is only for iteration. What are you trying to do?
> The example you've given is not a compelling use case,
> since you can simply remove the line after break.

Ok, I write a better example:

  var = ...something...

  case num
  when 1:
    puts "var not valid !!!!!" if ( var < 0 || var > 10 )
    break
    do_normal_stuff
    ...
    ...
    end_normal_stuff
  end

  puts "Write it"

I just want do_normal_stuff in case "var" is valid.
Yes, I can put a big "if" stament and so but I would like not to do it
since it makes a bit ugly the code.

But in this example the code between do_normal_stuff and end_normal_stuff
would never be executed, not even in C!

Opss, sorry, my mistake. This would be:

var = ...something...

  case num
  when 1:
    if ( var < 0 || var > 10 )
        puts "var not valid !!!!!"
        break
    end
    do_normal_stuff
    ...
    ...
    end_normal_stuff
  end

  puts "Write it"

Why not write something simpler

case num
when 1:
  if 0 <= var and var <= 10) then
   do_normal_stuff
   ...
   ...
   end_normal_stuff
   puts "Write it"
  end

Yes, but what I was trying to avoid is to enclose all the "real" stuff
ni a "if" stament since it's in fact the default behaviour and that
will be executed 99% of times.

Anyway I understand that is the only way.

Thanks a lot for all. :slight_smile:

···

2008/4/17, Peter Hickman <peter@semantico.com>:

--
Iñaki Baz Castillo
<ibc@aliax.net>

thanks for that info :wink:

···

2008/4/17, Stefan Lang <perfectly.normal.hacker@gmail.com>:

But be careful, catch/throw is dynamically scoped.
"ri catch" has more info.

--
Iñaki Baz Castillo
<ibc@aliax.net>

I would recommend using an "ordinary" exception - because that's what it is.

var = ...something...

case num
when 1:
   raise "var invalid!" if var < 0 || var > 10
   do_normal_stuff
   ...
   ...
   end_normal_stuff
end

puts "Write it"

Kind regards

robert

···

2008/4/17, Stefan Lang <perfectly.normal.hacker@gmail.com>:

2008/4/17, Iñaki Baz Castillo <ibc@aliax.net>:

> 2008/4/17, Stefan Lang <perfectly.normal.hacker@gmail.com>:

Well, since Ruby doesn't support it, you must find other
ways to structure the code in each case. Exceptions might
help in the bigger picture, splitting it up in smaller methods, etc.

You can use catch/throw for this:

--
use.inject do |as, often| as.you_can - without end

# var = ...something...
# case num
# when 1:
# if ( var < 0 || var > 10 )
# puts "var not valid !!!!!"
# break
# end
# do_normal_stuff
# ...
# ...
# end_normal_stuff
# end
# puts "Write it"
#....
# Yes, but what I was trying to avoid is to enclose all the "real" stuff
# ni a "if" stament since it's in fact the default behaviour and that
# will be executed 99% of times.
# Anyway I understand that is the only way.

how about another case way,

var = ...something...
case
  when num==1 and ( var < 0 || var > 10 )
     puts "var not valid for num==1 !!!!!"
  when other_stuff_condition
  when ....
     ...
  else
    else_stuff
end
puts "Write it"

kind regards -botp

···

From: Iñaki Baz Castillo [mailto:ibc@aliax.net]

I would recommend not to use an exception at all.

If I had the problem I would try to the following things in that order:
(a) restructure your case if this makes it more readable
(b) if not a local exit might make the code quite readable,
     if the case is used in a loop that well be "next", if the case is
a method body, which is often the case use "return"
(c) if neither (a) or (b) provide some appealing code, try to refactor
the case into a method
(d) and only if (c) makes no sense either use
     catch(:mylocalexit){
            case....
               throw :mylocalexit
     }

HTH
Robert

···

On Thu, Apr 17, 2008 at 4:14 PM, Robert Klemme <shortcutter@googlemail.com> wrote:

2008/4/17, Stefan Lang <perfectly.normal.hacker@gmail.com>:
> 2008/4/17, Iñaki Baz Castillo <ibc@aliax.net>:
>
> > 2008/4/17, Stefan Lang <perfectly.normal.hacker@gmail.com>:

> Well, since Ruby doesn't support it, you must find other
> ways to structure the code in each case. Exceptions might
> help in the bigger picture, splitting it up in smaller methods, etc.
>
> You can use catch/throw for this:

I would recommend using an "ordinary" exception - because that's what it is.

--
http://ruby-smalltalk.blogspot.com/

---
Whereof one cannot speak, thereof one must be silent.
Ludwig Wittgenstein

opss, I didn't know that a "when" can contain a comparision, nice to know!

Thanks.

···

El Viernes, 18 de Abril de 2008, Peña, Botp escribió:

how about another case way,

var = ...something...
case
  when num==1 and ( var < 0 || var > 10 )
     puts "var not valid for num==1 !!!!!"
  when other_stuff_condition
  when ....
     ...
  else
    else_stuff
end
puts "Write it"

--
Iñaki Baz Castillo

It can contain any expression, but it will not do what you want.
The semantics of case is the following

  case e
     when e1
        a1
     when e2
       a2
    else
       a3
   end

if e1 === e then
    a1
elsif e2 === e then
   a2
else
  a3
end

unfortunately
  case e
     when true
        a

will only work for e == true as
true === Object.new --> false

maybe Matz did not want to allow logical comparision in case :wink:

but he gave us the power to overrule

try the following code with the line commented and then uncommented and
you will see what is going on

class TrueClass
# def === any; true end
end

case 42
   when true
      p true
   else
      p :else
end
HTH
R.

···

On Fri, Apr 18, 2008 at 8:52 PM, Iñaki Baz Castillo <ibc@aliax.net> wrote:

El Viernes, 18 de Abril de 2008, Peña, Botp escribió:

> how about another case way,
>
> var = ...something...
> case
> when num==1 and ( var < 0 || var > 10 )
> puts "var not valid for num==1 !!!!!"
> when other_stuff_condition
> when ....
> ...
> else
> else_stuff
> end
> puts "Write it"

opss, I didn't know that a "when" can contain a comparision, nice to know!

--
http://ruby-smalltalk.blogspot.com/

---
Whereof one cannot speak, thereof one must be silent.
Ludwig Wittgenstein

Interesting, nice to know :slight_smile:

···

El Viernes, 18 de Abril de 2008, Robert Dober escribió:

try the following code with the line commented and then uncommented and
you will see what is going on

class TrueClass
# def === any; true end
end

case 42
   when true
      p true
   else
      p :else
end

--
Iñaki Baz Castillo

Sure it will. There are two different forms of case, the form
case
  when foo1 then bar1
  when foo2 then bar2
  ...
  else baz
end

Works exactly as described above.

You could do it with the other kind of case (the one whose semantics
you describe),
but it would be a bit uglier. E.g.,

case num
  when (if var.between? 0, 10 then 1 else Object.new) then do_normal_stuff
  when 1 then do_error_stuff
  ...
end

···

On Fri, Apr 18, 2008 at 1:40 PM, Robert Dober <robert.dober@gmail.com> wrote:

On Fri, Apr 18, 2008 at 8:52 PM, Iñaki Baz Castillo <ibc@aliax.net> wrote:
> El Viernes, 18 de Abril de 2008, Peña, Botp escribió:
>
>
> > how about another case way,
> >
> > var = ...something...
> > case
> > when num==1 and ( var < 0 || var > 10 )
> > puts "var not valid for num==1 !!!!!"
> > when other_stuff_condition
> > when ....
> > ...
> > else
> > else_stuff
> > end
> > puts "Write it"
>
> opss, I didn't know that a "when" can contain a comparision, nice to know!
It can contain any expression, but it will not do what you want.

>
> >
> >
> > > how about another case way,
> > >
> > > var = ...something...
> > > case
> > > when num==1 and ( var < 0 || var > 10 )
> > > puts "var not valid for num==1 !!!!!"
> > > when other_stuff_condition
> > > when ....
> > > ...
> > > else
> > > else_stuff
> > > end
> > > puts "Write it"
> >
> > opss, I didn't know that a "when" can contain a comparision, nice to know!
> It can contain any expression, but it will not do what you want.

Sure it will. There are two different forms of case, the form

First my appologies for my error, I did not see that the case part was
empty, my fault

case
  when foo1 then bar1
  when foo2 then bar2
  ...
  else baz
end

Works exactly as described above.

You could do it with the other kind of case (the one whose semantics
you describe),
but it would be a bit uglier. E.g.,

case num
  when (if var.between? 0, 10 then 1 else Object.new) then do_normal_stuff
  when 1 then do_error_stuff
  ...
end

my point is however that of course you lose the basic feature you
wanted but we have two possibilities here, either monkeypatching
TrueClass and using the !! form to convert any logical true value to
the real single true value, than the code might look like this

case expression
    when /abc/
        ...
     when !! get_an_object(expression)
        ...

I have to admit that the monkey patch is just not an option if you are
writing a library and is a feature too often abused anyway.

I therefore suggest to follow Christopher's approach even if the code
gets a little bit uglier (but beauty lies in the eyes of the
beholder).

case
    when /abc/ === expression
       ...
    when get_an_object( expression )
       ...
end

Sorry again, I outsmarted myself :wink:

Cheers
Robert

···

On Sat, Apr 19, 2008 at 7:59 PM, Christopher Dicely <cmdicely@gmail.com> wrote:

On Fri, Apr 18, 2008 at 1:40 PM, Robert Dober <robert.dober@gmail.com> wrote:
> On Fri, Apr 18, 2008 at 8:52 PM, Iñaki Baz Castillo <ibc@aliax.net> wrote:
> > El Viernes, 18 de Abril de 2008, Peña, Botp escribió:

--
http://ruby-smalltalk.blogspot.com/

---
Whereof one cannot speak, thereof one must be silent.
Ludwig Wittgenstein