Peter V.
Peter V.

Reputation: 31

given - when statement doesn't work properly ('Learning Perl' Chapter 15 issue)

The example of using the given-when statement presented in chapter 15 of the "Learning Perl" book does not work properly. I'm using Perl v5.22.1. and I tried to reproduce the following code (see "Learning Perl", fifth edition, page 227.):

    use 5.010;
    given ($ARGV[0])
    {
       when(/fred/i) {say "Name has fred in it"; continue}
       when(/^Fred/) {say "Name starts with Fred"; continue}
       when('Fred')  {say "Name is Fred";}
       default {say "I don't see a Fred"}
    }

When I run the script, I get the following result:

D:\>Perl D:\Perl\Example113.pl Frederick
given is experimental at D:\Perl\Example113.pl line 5.
when is experimental at D:\Perl\Example113.pl line 7.
when is experimental at D:\Perl\Example113.pl line 8.
when is experimental at D:\Perl\Example113.pl line 9.
Name has fred in it
Name starts with Fred
I don't see a Fred

As you can see, the default block works contrary to expectations. At the same time if you swap first and last blocks 'when', it is works almost as described in the book:

    use 5.010;
    given ($ARGV[0])
    {
       when('Fred')  {say "Name is Fred"; continue}
       when(/^Fred/) {say "Name starts with Fred"; continue}
       when(/fred/i) {say "Name has fred in it"; }
       default {say "I don't see a Fred"}
    }

What gives us the next output:

D:\>Perl D:\Perl\Example113.pl Frederick
given is experimental at D:\Perl\Example113.pl line 5.
when is experimental at D:\Perl\Example113.pl line 7.
when is experimental at D:\Perl\Example113.pl line 8.
when is experimental at D:\Perl\Example113.pl line 9.
Name starts with Fred
Name has fred in it

Am I doing something wrong or in the book is an incorrect example?

Upvotes: 0

Views: 261

Answers (2)

zdim
zdim

Reputation: 66899

First, while exploration and play is good I must repeat what perlsyn says

As previously mentioned, the "switch" feature is considered highly experimental; it is subject to change with little notice.

If that isn't enough, here is a bit more, earlier in perlsyn

Exactly what the EXPR argument to when does is hard to describe precisely, but in general, it tries to guess what you want done. Sometimes it is interpreted as $_ ~~ EXPR, and sometimes it does not. It also behaves differently when lexically enclosed by a given block than it does when dynamically enclosed by a foreach loop. The rules are far too difficult to understand to be described here. See Experimental Details on given and when later on.

I don't know what to think about a feature which "is hard to describe precisely." Also note that "Most of the power comes from the implicit smartmatching" (same page). What matters is that it seems crystal clear that this will change, and very likely significantly.

Having cleared that up, the behavior you show is expected. From the example in perlsyn

given ($foo) {
    when (undef) {
        say '$foo is undefined';
    }
    when ("foo") {
       say '$foo is the string "foo"';
    }
    ...
}

where $foo need be equal to the string "foo", not matched by it; this isn't a regex match but string equality.

In your examples the string 'Fred' is not equal to Frederick. In the second one there is that continue so it does go to the next branch, but in the first one there isn't (while it's also last before default). Run the program with input Fred to see.

Upvotes: 5

ikegami
ikegami

Reputation: 386351

Without continue, when and default exit the surrounding given or move to the next item of the surrounding for.

With continue, execution proceeds with the next statement.

The default block is unconditionally executed when reached.


For example,

given ($ARGV[0]) {
    say "Checking for 'x'";
    when (/x/) { say 'contains an x'; continue; }
    say "Checking for 'y'";
    when (/y/) { say 'contains a y';            }
    default    { say 'does not contain a y';    }
}

For y:

Checking for 'x'
Checking for 'y'
contains a y

For x:

Checking for 'x'
contains an x
Checking for 'y'
does not contain a y

For xy:

Checking for 'x'
contains an x
Checking for 'y'
contains a y

Upvotes: 1

Related Questions