Why is parenthesis optional only after sub declaration?

后端 未结 4 1135
栀梦
栀梦 2020-12-05 23:40

(Assume use strict; use warnings; throughout this question.)

I am exploring the usage of sub.

sub bb { print @_; }         


        
4条回答
  •  误落风尘
    2020-12-05 23:56

    I think what you are missing is that Perl uses a strictly one-pass parser. It does not scan the file for subroutines, and then go back and compile the rest. Knowing this, the following describes how the one pass parse system works:

    In Perl, the sub NAME syntax for declaring a subroutine is equivalent to the following:

    sub name {...}   ===   BEGIN {*name = sub {...}}
    

    This means that the sub NAME syntax has a compile time effect. When Perl is parsing source code, it is working with a current set of declarations. By default, the set is the builtin functions. Since Perl already knows about these, it lets you omit the parenthesis.

    As soon as the compiler hits a BEGIN block, it compiles the inside of the block using the current rule set, and then immediately executes the block. If anything in that block changes the rule set (such as adding a subroutine to the current namespace), those new rules will be in effect for the remainder of the parse.

    Without a predeclared rule, an identifier will be interpreted as follows:

    bareword       ===   'bareword'   # a string
    bareword LIST  ===   syntax error, missing ','
    bareword()     ===   &bareword()  # runtime execution of &bareword
    &bareword      ===   &bareword    # same
    &bareword()    ===   &bareword()  # same
    

    When using strict and warnings as you have stated, barewords will not be converted into strings, so the first example is a syntax error.

    When predeclared with any of the following:

    sub bareword;
    use subs 'bareword';
    sub bareword {...}
    BEGIN {*bareword = sub {...}}
    

    Then the identifier will be interpreted as follows:

    bareword      ===   &bareword()     # compile time binding to &bareword
    bareword LIST ===   &bareword(LIST) # same
    bareword()    ===   &bareword()     # same
    &bareword     ===   &bareword       # same
    &bareword()   ===   &bareword()     # same
    

    So in order for the first example to not be a syntax error, one of the preceding subroutine declarations must be seen first.

    As to the why behind all of this, Perl has a lot of legacy. One of the goals in developing Perl was complete backwards compatibility. A script that works in Perl 1 still works in Perl 5. Because of this, it is not possible to change the rules surrounding bareword parsing.

    That said, you will be hard pressed to find a language that is more flexible in the ways it lets you call subroutines. This allows you to find the method that works best for you. In my own code, if I need to call a subroutine before it has been declared, I usually use name(...), but if that subroutine has a prototype, I will call it as &name(...) (and you will get a warning "subroutine called too early to check prototype" if you don't call it this way).

提交回复
热议问题