March 3, 2015 by Daniel P. Clark

Ruby: The Case for Case

It’s nice to have case and when available in Ruby.  But I don’t see it used too often.  I myself don’t use it much because I’m more accustomed to just using if and else.  So let’s get into case switching.

This is your standard use of  case switching.  We check whatever variable is handed to case against each when condition.  If they match then that section of code is executed and the rest won’t be evaluated.

Alternatively you can just not hand a value to case and use when like you would with if and else.

Those are the simplest usages for case.  But wait!  It gets better.  You can evaluate the Object handed to case with a Proc in your when clause.

Proc it!

So what happens if we do a method call as the case parameter?  Lets use Time.now .  I’ll use Procs with print statements to show whether we’re getting changing information.

So from this we see that the method handed to case is executed and evaluated to a hidden internal variable from which to compare.  So it acts just like a variable for something handed to case.  Why do I say hidden?  Because there is no way to evaluate the case item inside the when block; if it’s not defined outside of case.  See here:

Here we see our inner proc with y isn’t being given any arguments which is raising an error for us.  So the when clause will get handed the object to evaluate, but the code within the when block doesn’t get to see it.  Of course this isn’t an issue if you simply assign a variable before the case statement; then it’s available throughout.

Regex

You may use regex to evaluate your case variable.

Perhaps evaluating whether a string is upper case or lower case would be the most contextually appropriate use for case ;-).  Just kidding of course.  There are methods for that.

Caution, Weirdness, Don’t Do This

Now it is possible to change the object during the when evaluation.  This can lead to none of the cases ever evaluating as true.

For this same reason it’s probably not a great idea to use a Proc as a case switch with something that changes like Time.now .

So you can see that the Proc calls a fresh result from Time.now in each when case and the time has changed between each.  So in this case you may never hit the when clause even though one of the when clauses may be true at one point during the evaluation.  Is this likely?  Probably not.  But it is possible.

You can case case statements.  A case statement returns a result just like anything else in Ruby and you can check another case against it.  Is this useful?  I don’t know.  There may be an excellent use case for it somewhere in the future.  But the more I think about it the more I think it’s not advisable.

Additional Notes

I’ve touched on self recursive (tail recursive) methods once or twice.  Aja Hammerly uses case statements for some of her conference talk demonstrations.  It was from her conference talk up on Youtube from which I learned that you can call case without passing it something to evaluate.

In my mind it’s mostly preference that leads to using if and else over case.  But at times it may be more elegant to use case.  What do you think?  What’s the best use case for case?  Also do you know of any other behaviors or oddities with case?  I’d really like to hear about it!

Hope this was both enlightening and enjoyable for you!  Please feel free to comment, share, subscribe to my RSS Feed, and follow me on twitter @6ftdan!

God Bless!
-Daniel P. Clark

Image by Tom Godber via the Creative Commons Attribution-ShareAlike 2.0 Generic License.

#case#else#if#lambda#proc#ruby#switch#switching#when

15
Leave a Reply

avatar
5 Comment threads
10 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
7 Comment authors
Robert FletcherWilson SilvaKeith BennettcrazymyklKevin Thompson Recent comment authors
  Subscribe  
newest oldest most voted
Notify of
Bob Nadler Jr.
Guest

Nice post! I tend to stay away from writing long case or if/else statements, but I learned some interesting properties about the case statement reading this.

Daniel P. Clark
Guest

I’m glad you’ve found this useful for you.

Kevin Thompson
Guest

Great article! There might actually be a use case for passing methods or procs that contain complex logic. The one thing that came to mind that you didn’t cover was when statements accepting multiple values. Ruby [crayon-5c99c2736e5ea289244629 class="ruby"] between_zero_and_two = -> (x) { x.between?(0, 2) } equal_to_one = -> (x) { x == 1 } case 1 when 3, 4, 5 p 'More than two, less than six.' when between_zero_and_two, equal_to_one p 'One' else p 'Something else' end 12345678910111213  [crayon-5c99c2736e5ea289244629   class="ruby"]between_zero_and_two = -> (x) { x.between?(0, 2) }equal_to_one = -> (x) { x == 1 } case 1when 3, 4, 5  p… Read more »

Daniel P. Clark
Guest

Awesome! Thanks for the tip! I wasn’t aware of it.

Robert Fletcher
Guest
Robert Fletcher

You can use ranges for this as well:

[/crayon]

crazymykl
Guest
crazymykl

Firstly, nice article. This is a good introduction to the case statement, although it’s missing a very common use case. Case statements are often used to switch on t he type of the argument, which I didn’t see an example of here. Also, it would’ve been nice to mention that case works on all these predicates by invoking #=== on them, so you can customize the behavior of your own classes in case statements. Finally, proc and lambda are not interchangable in Ruby, procs do not get their own stack frame (so return statements will take you out of the… Read more »

Daniel P. Clark
Guest

Thanks! I’m very interested in seeing how that common use type is implemented; “switch on the type of argument”. Could you provide some sample code for that? I had seen it mentioned about the triple equals evaluation. I hadn’t heard it explained in quite that way. Is that the exclusive way the case/when checks things? Is that calling .call() on procs/lambdas by evaluating the #=== method on them? I was aware about ->{ } syntax being lambdas. Correct me if I’m wrong, but as I’ve been told: All lambdas are procs, not all procs are lambdas, and what’s commonly referred… Read more »

Keith Bennett
Guest
Keith Bennett

Dan – Nice article. I didn’t know that case could be used without a case variable. I like the idea of using case when’s instead of elsif’s. For some reason it seems more readable to me. I’ve never heard of stabby proc, but I have heard of stabby lambdas; but as I understand it, the ‘stabby’ refers only to the ‘->’ notation and has nothing to do with the object produced. Regarding procs and lambdas, it is unfortunate that in Ruby it’s fuzzy. Perhaps the best way to think of it as that a Proc can be either a proc… Read more »

Daniel P. Clark
Guest

Hey Keith, I’ve never heard of stabby lambda. Jim Weirich called them stabby procs as well as other well known keynote speakers. You can hear Jim Weirich call it a stabby proc at about 15 minutes and 48 seconds in on his “Y Not- Adventures in Functional Programming” talk. So this, and other sources like it, is where I learned about stabby proc. Do you think I’d be alright with referring to lambdas with the upper case Proc? Is that considered the category identifier for both procs and lambdas? Since lambdas are a kind of proc I’d like to be… Read more »

Keith Bennett
Guest
Keith Bennett

Hi, Dan. I didn’t know that, but you’re right, he did call them stabby…Procs? They are Procs but not procs….that is, the code I posted above proves that they are lambdas and not procs. Given that Procs and procs are indistinguishable when spoken, I usually say lambda and non lambda procs when I need to differentiate them. Since lambdas and non lambda procs behave differently, I think it’s important to be precise. If what you’re saying applies to both, of course, it doesn’t matter, and Proc is fine in writing; when speaking I will sometimes say ‘lambdas and non lambda… Read more »

Wilson Silva
Guest

I like your writings. I wish you had a newsletter.

Daniel P. Clark
Guest

Thanks! What is it you’re looking for in a newsletter? Blog posts delivered to your e-mail address?

Wilson Silva
Guest

Yes

Robert Fletcher
Guest
Robert Fletcher

A fun alternative to your

example, though not necessarily better:

[/crayon]

Daniel P. Clark
Guest

Thanks! Yeah I’ve been trying to think of place to use Float::INFINITY myself so this definitely fits the bill! 😉