As a statement modifier, the expression before the when has an implicit break when you use it with given or an implicit next when you use it with foreach. That is, once a when condition evaluates to true, Perl doesn’t continue with the rest of the block.

You’re still supposed to use when inside a topicalizer (e.g. foreach or given). You might be tempted to use it more liberally so you can take advantage of its implicit smart matching anywhere that you like. A curious and perhaps unintended parsing makes it a runtime error instead of a compilation error:

The while isn’t a topicalizer, even though in this particular idiom it sets $_ for you. You get the output along with a warning:

$ perl5.12.1 no-topicalizer.pl
Buster
Found cat with id []
Can't use when() outside a topicalizer at test line 11, <STDIN> line 1.

However, you don’t get a fatal error when the condition is false, which is probably another bug (filed as RT #77510). There’s no fatal error, no warning message, and the output shows that Perl kept going:

Ella
Mimi
Found cat with id 123
Can't use when() outside a topicalizer at test line 11, <STDIN> line 2.

Just because it it does just what you think it should do then dies telling you it doesn’t do that, don’t think you should do it. You could use eval to catch the fatal error, but that’s a kludge that will only work until the Perl developers fix the problem. Besides, if you are going to go that far, it’s just as easy to make the smart match explicit with an if statement modifier (and that is even backward compatible with 5.10):

The only question now is how long you will be able to use this before your Perl::Critic policies update to forbid it, whether inside or outside of a topicalizer. Use it while you can: time is running out.

3 Comments.

This was really nice. I did not know you could use when() as a statement modifier. One minor thing that was confusing to me was where you wrote “As a statement modifier, the expression before the when has an implicit break …”. From my first reading of that, I thought the implicit break happened only when you use when() as a statement modifier, as opposed to the traditional way. It might be better to write that as, “The when expression has an implicit break …”

Asking why while isn’t a topicalizer the same answer as asking why if isn’t one. It’s not what they do. The while( <FH>) idiom is just a special case that happens to set $_ for you, but only in that one case. Most of the possible uses of while don’t set $_ or a named control variable, while all of the uses of the topicalizers do.