3

I'm running Perl scripts version 5.28 under Linux Debian with some experimental "extensions" and got an strange behavior. In a mixed Pascal-SQL-Perl programming session, I miss typed a lowercase begin instead of an else in an if-else-statement (see test code below) and got an valid but malfunctioning code.

I'm aware that the uppercase BEGIN keyword belongs to BEGIN, UNITCHECK, CHECK, INIT and END program "pre- and post-program-running" group. But I used the lowercase begin variant and I got a valid running code. It seems to me, that the begin {...} block is executed separately after the if (...) {...} expression, which causes an unwanted early return.

Has the lowercase begin any meaning in a Perl case sensitive programming context?

#!/usr/bin/perl
use v5.20;
use strict;
use warnings;
use feature qw(signatures);
no warnings 'once';
no warnings 'experimental';
no warnings 'experimental::signatures';

&if_exotic(1000);
&if_normal(1000);

# --------------------------------------
# Bad variant
# --------------------------------------
sub if_exotic($want) {

   if ($want>0) {
       print "BAD: ..running $want operations\n";
   } begin {
       print "BAD: ..nothing to do\n";
       return;
   }

    print "Do something $want times\n";
   
}

# --------------------------------------
# Good variant
# --------------------------------------
sub if_normal($want) {

   if ($want>0) {
       print "GOOD: ..running $want operations\n";
   } else {
       print "GOOD: ..nothing to do\n";
       return;
   }

    print "Do something $want times\n";
}

/usr/bin/perl "test-if-begin"
BAD: ..running 1000 operations
BAD: ..nothing to do
GOOD: ..running 1000 operations
Do something 1000 times
toolic
  • 57,801
  • 17
  • 75
  • 117
huckfinn
  • 644
  • 6
  • 23
  • Related: [Why is this program valid? I was trying to create a syntax error](https://stackoverflow.com/q/11695110/589924) – ikegami Aug 02 '23 at 17:39

1 Answers1

9

This is Perl's indirect object notation in action.

It allows the (recommended) syntax

PackageName->method(args-list)

to be written as (a "discouraged")

method PackageName arg-list

Let's boil down the example program to

use warnings;
use strict;

indirect_notation_gotcha();

print "all good?\n";

sub indirect_notation_gotcha {

    anyword {
        print "This body stands for package name\n";
        return;                                      # runs before "anyword"
    }

}

By the indirect-object syntax the code inside the sub is equivalent to

do {
    print "This body stands for package name\n";
    return
} -> anyword;

This is legal syntax and at runtime the return statement is what "saves" it as it never gets to the non-existent anyword.

If we drop the return

indirect_notation_gotcha();

print "all good?\n";

sub indirect_notation_gotcha {
    anyword {
        print "This body stands for package name\n";
    }
}

Now the anyword is attempted and we get

This body stands for package name
Can't locate object method "anyword" via package "1" (perhaps you forgot to load "1"?) at ...

As shown in the link on top, in newer Perls this is a feature that can be disabled (with v5.32+)

 no feature qw(indirect);  # v5.32+

In yet newer Perls it gets disabled in the bundle as well

use v5.36; 

See perldelta for 5.36.0.

zdim
  • 64,580
  • 5
  • 52
  • 81