Does do-given work right?

[This is now [perl #93548]]

Perl 5.14 added a return value to given if you put it inside a do. However, it looks like that return value can't be a value in a lexical variable the you define inside the given:

#!/usr/local/perls/perl-5.14.1/bin/perl

use 5.014;

my $foo = 'foo!';

foreach my $string ( qw(foo bar baz quux hoo) ) {
    my $got = do {
        my $bar = 'bar!';
        given( $string ) {
            my $baz = 'baz!';

            when( 'quux' )    { my $quux = 'quux!' }
            when( 'foo' )     { $foo               }
            when( 'bar' )     { $bar               }
            when( 'baz' )     { $baz               }
            default           { 'default'          }
            }
        };

    say "$string got: $got";
    }

This gives me:

foo got: foo!
bar got: bar!
baz got: 
quux got: 
hoo got: default

What am I doing wrong there?

11 Comments

I have no experience with the new syntax, but I'm wondering: does it work if you do anything to $baz, for example quoting it or otherwise use it in an expression?

I suppose it might be using an alias, and once the original is wiped, so is your alias. Using it in an expression would make a copy.

All of the examples that I just looked up never show defining a variable like that with the "given" statement. So I would assume that "no, you aren't supposed to do that."

I hadn't even realize you could put non-when statements directly into a given. For that matter, I'm not sure it's a good idea to do so -- while I can see where it would let you eliminate duplicated code, I can't help thinking it would make the code less clear when you came back to it in six months/a year/half a decade.

Just a guess: the my $baz part never gets executed. So there is no $baz variable really.

Also, the "my $quux" part I suspect does not return 'quux'. Maybe it should be something like my $quux = 'quux'; $quux

Best regards,
Athanasios

In 5.10.1, at least, the my $baz part does get executed (I tried adding non-when statments to a given, just to see, because I was surprised that it would work).

If "my $foo = 'bar'" didn't return bar, things like while(defined(my $line=<$fh>)) wouldn't work anymore.

I toyed with it a bit...
Haven't found anything helpful,
but did discover something interesting:

The same thing happens with local...

if you declare our $quux in main and change:

-            when( 'quux' )    { my $quux = 'quux!' }
+            when( 'quux' )    { local $quux = 'quux!' }

you still get nothing.

Of course if you drop the "local" then you get the expected output.

is "when" in some sort of self-destructing air tight container?

I don't even know where to start looking for that in the perl source... grepping (ack'ing?) for "given" or "when" is not very fruitful.

Hi,

Yes you are right, my mistake. But confusingly, the 'default' actually comes through.

dstar:

It is not only possible, it is an advertised and intended feature that you can put any code directly inside a given (or, obviously, a for – which you can also place whens into).

Perl didn’t have a switch statement for a very long time because Larry famously considered the design included in other languages to suck. The inability to share code between branches in this way was a major part of that.

Looks like this has been fixed.

$ perlbrew switch /.../perl5.15.0 perl5.15.0-2011-06-26
Switched to /.../perl5.15.0 as perl5.15.0-2011-06-26
08:03 ~/src/perl-foo 
$ perl bdfoy-test.pl
foo got: foo!
bar got: bar!
baz got: baz!
quux got: quux!
hoo got: default

Leave a comment

About brian d foy

user-pic I'm the author of Mastering Perl, and the co-author of Learning Perl (6th Edition), Intermediate Perl, Programming Perl (4th Edition) and Effective Perl Programming (2nd Edition).