http://qs1969.pair.com?node_id=1069290

morelenmir has asked for the wisdom of the Perl Monks concerning the following question:

I began using the 'given/when' keywords a couple of weeks back - which are a nice edition in my opinion and make perl that bit more C'ish. However, after finally getting around to downloading the newest "StarberryPerl" this morning I have started to see 'given is experimental' and 'when is experimental' warnings. On consulting the fascinating "PerlDelta" page it seems it is more a question of 'smartmatch' being up for change/deprecation than 'given' itself. However the warnings are still there and the documentation is vague... I think I could specifically switch that warning off, but I do not want to get used to what for me would be a fairly staple code construct and then have it vanish when 5.20 appears.

Do any of you chaps know for sure if 'given' is doomed/safe? Do you use it heavily in your own programmes?

Replies are listed 'Best First'.
Re: perldelta unclear on 'given's fate
by tobyink (Canon) on Jan 04, 2014 at 17:13 UTC

    I imagine that given/when will be kept. However, the perception is that their current implementation is highly flawed. A new implementation will probably break some existing uses of given/when, so it makes sense to start warning people about this.

    given originally used the lexical $_ rather than the global $_ (but this has changed in 5.18). This was confusing for many people.

    when adds a whole extra layer of weird.

    Quick quiz! What does this output?

    use v5.10; use strict; no warnings; sub two () { 2 } sub three { 3 } sub english_number { my $number = shift; given ($number) { when ( 1 ) { return 'one' } when ( two ) { return 'two' } when ( three ) { return 'three' } when ( 4 ) { return 'four' } default { return 'more' } } } say english_number($_) for 1..5;
    use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
      A whole extra layer of weird indeed. I couldn't guess so I ran it... weirder than I expected. Can you please explain what's going on here?

        It basically comes down to a question of why does when(two) seem to work as expected, but when(three) screw up everything below it?

        when(EXPR) can mean two different things. It sometimes means if($_ ~~ EXPR), and it sometimes means if(EXPR). The rules by which the interpretation of when is decided are fairly convoluted, and have changed from Perl version to Perl version. In this case they're fairly easily explained.

        three is a sub call, so when(three) is interpreted as if(three). The three sub returns 3, so this condition always evaluates to true. Thus the subsequent condition when(4) and the default clause will never get triggered.

        two is a simple sub with a prototype of () though. Thus Perl treats it as a constant. It inlines the return value 2 when the when(two) is compiled. So Perl sees the condition as when(2) - that is, not a sub call at all - and interprets it as meaning when($_ ~~ 2).

        use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name

      Hmmm...

      I actually had to run that to work it out!

      It prints "one, two, three, three, three" because the 'three' routine resets the global $_ every time the flow of execution reaches it I think? But... why doesn't the same happen with the 'two ()' routine... Something to do with the parentheses - does that sub not effect the global $_?

      That's quite a mind-twister!!!

Re: perldelta unclear on 'given's fate
by toolic (Bishop) on Jan 04, 2014 at 15:20 UTC
    The current (5.18.0) perlsyn refers to given as "highly experimental". But, it also implies that foreach can be used in its place and is "non-experimental".

      Yep, sure enough. That method of using 'foreach' looks to be almost identical to 'given' and provides nearly the same results. Although I will say manhandling 'foreach' to work like this seems more of bodge than having a proper 'switch' analogue.

      For now I'll follow you're advice toolic and swap over to 'foreach' until it is clear one way or the other if 'given' is going to make the cut.

      Reading that "perlsym" page and indeed, other posts here and at "stackoverflow" I get the feeling there is a fair bit of hostility towards poor old 'given/when'. Can you fill me in on why that might be?

      However... On trying it I still get warnings for 'when'. So... I guess the safest thing is just to trudge on with an ugly if/elsif construct for now.

Re: perldelta unclear on 'given's fate
by ikegami (Patriarch) on Jan 06, 2014 at 11:45 UTC

    There are problems with the design of smart-matching. The decision of what any given TYPE ~~ TYPE should do is most often unobvious, inconsistent and/or disputed. The idea isn't to remove smart matching; it's to fix it.

    Specifically, ~~ will likely be greatly simplified, as you can see in a proposal by the 5.18 pumpking. Decisions as to how two things should match will be done with helpers such as those that already exist in Smart::Match.

    ... ~~ any(...)

    Much more readable, much more flexible (fully extensible), and solves a number of problems (such as "When should X be considered a number, and when should it be considered a string?").


    Along the same lines, the rules for when when uses smart-matching and when it doesn't are complicated. I suspect that will change.


    Lexical $_ (currently used by given) apparently causes too much problems. For example, the following code doesn't work because first sets package variable $_, but the callback captured the lexical $_ declared by given.

    given (...) { ... first { /.../ } ... ... }

    Rather than continuing to require callbacks to use our $_;, given will be changed to use package variable $_ instead of lexical $_ in 5.20.

Re: perldelta unclear on 'given's fate
by morelenmir (Beadle) on Jan 04, 2014 at 18:29 UTC

    I shall give all those suggestions a look over chaps! From what has been said here it looks like the desire for a perl 'switch' has been around for quite a long time.

    LanX - in regards your snippet; if I understand aright the 'if's are comparing implicitly against $_ without having to explicitly provide a second argument? I am still very woolly about those perl shortcuts!

    Either way, the 'next's work like 'break' would in C?

Re: perldelta unclear on 'given's fate
by doom (Deacon) on Jan 06, 2014 at 20:02 UTC
    There have been a lot of discussions of problems with the current implementation of given/when, but all of them tend to be with fairly unusual cases, in my opinion. If you stick to it's basic, obvious uses and don't expect too much from it, I would guess you're unlikely to regret using it: the perl-porters aren't going to mess with the basic behaviour, they just want to get rid of a lot of edge case problems.
      Sounds fair enough doom!
      "Aure Entuluva!" - Hurin Thalion at the Nirnaeth Arnoediad.