given/when – the Perl switch statement
Its been a while since my last post; summer holidays have inflicted upon me some big distractions! So to ease myself back in gently I’ll I’ve pulled out a (nearly finished but unposted) article from last year (in true Blue Peter tradition!)
This post was inspired by this nice & straightforward blog article: How A Ruby Case Statement Works And What You Can Do With It. I’ve simply converted the Ruby code to Perl and added some so called insightful notes 🙂
Now what Ruby calls case/when
statements is more commonly known in computer parlance has the switch statement.
Perl itself has had such a switch statement for quite a while now:
use Switch; switch ($grade) { case "A" { say "Well done!" } case "B" { say "Try harder!" } case "C" { say "You need help!!!" } else { print "You just making it up" } }
However DON’T USE IT!!! Its a source filter and is being deprecated.
Instead use given/when which is the Perl 6 switch statement that was introduced at perl 5.10.
use strict; use warnings; use feature qw(switch say); print 'Enter your grade: '; chomp( my $grade = <> ); given ($grade) { when ('A') { say 'Well done!' } when ('B') { say 'Try harder!' } when ('C') { say 'You need help!!!' } default { say 'You are just making it up!' } }
And at perl 5.12 you could also use when
has a statement modifiers:
use 5.012; use warnings; print 'Enter your grade: '; chomp( my $grade = <> ); given ($grade) { say 'Well done!' when 'A'; say 'Try harder!' when 'B'; say 'You need help!!!' when 'C'; default { say 'You are just making it up!' } }
And even more enhancements are coming with perl 5.14 because given
now returns the last evaluated expression:
use 5.013; # 5.014 use warnings; print 'Enter your grade: '; chomp( my $grade = <> ); say do { given ($grade) { 'Well done!' when 'A'; 'Try harder!' when 'B'; 'You need help!!!' when 'C'; default { 'You are just making it up!' } } };
Which can lead to some very pleasant looking dry code.
But there is more to given/when
than just single value conditionals. You can also check multi-values and ranges:
use 5.012; use warnings; print 'Enter your grade: '; chomp( my $grade = <> ); given ($grade) { say 'You pretty smart' when ['A', 'B']; say 'You pretty dumb!!' when ['C', 'D']; default { say "You can't even use a computer" } }
And also pattern match using a regex:
use 5.012; use warnings; print 'Enter some text: '; chomp( my $some_string = <> ); given ($some_string) { say 'String has numbers' when /\d/; say 'String has letters' when /[a-zA-Z]/; default { say "String has no numbers or letters" } }
In fact you can use anything that Smart Matching can resolve.
And because smart matching is used under the hood by given/when
then you can customise it by overloading the ~~
smart match operator:
use 5.012; use warnings; { package Vehicle; use Moose; use overload '~~' => '_same_wheels', fallback => 1; has number_of_wheels => (is => 'rw', isa => 'Int'); sub _same_wheels { my ($self, $another_vehicle) = @_; $self->number_of_wheels == $another_vehicle->number_of_wheels; } } my $four_wheeler = Vehicle->new( number_of_wheels => 4 ); my $two_wheeler = Vehicle->new( number_of_wheels => 2 ); my $robin_reliant = Vehicle->new( number_of_wheels => 3 ); print 'Enter number of wheel for vehicles: '; chomp( my $wheels = <> ); my $vehicle = Vehicle->new( number_of_wheels => $wheels ); given ($vehicle) { say 'Vehicle has the same number of wheels as a two-wheeler!' when $two_wheeler; say 'Vehicle has the same number of wheels as a four-wheeler!' when $four_wheeler; say 'Gosh... is that Del Trotter!!' when $robin_reliant; default { say "Don't know of a vehicle with that wheel arrangement!" } }
Hopefully that was a nice lightweight introduction to given/when
. And I haven’t even touched upon break or continue 🙂
/I3az/
This was a really good overview of given/when. I wanted to subscribe to your rss feed, but the rss link on the right side is broken. At least for my browser, google chrome.
Many thanks Naveed.
Regarding RSS… it works fine in Safari so I don’t know if its a chrome only issue? The URL for the article feed is https://transfixedbutnotdead.com/feed/ (and for the comments its https://transfixedbutnotdead.com/comments/feed).
BTW, you can also find this blog post aggregated with other Perl blogs on http://ironman.enlightenedperl.org/ & http://perlsphere.net/
regards Barry
This post got linked to on #perl6 IRC channel: http://irclog.perlgeek.de/perl6/2010-09-30
NB. This article was “Hacker News”-ed (!) a couple of weeks ago: http://news.ycombinator.com/item?id=2132517
Thanks for the examples. I was about to use a switch
pretty cool,Both given/when and your post.
Very good examples on given. Thank you.
Why do the people who decide on Perl syntax so often choose to take existing, well-known constructs and give them different names JUST TO CONFUSE EVERYBODY? It seems deliberately evil.
If its an improvement then I’m all for it. And I would definitely say given/when is a great improvement over switch/case (and variants).