Perl Subroutine Prototyping — The correct way to do it

后端 未结 5 1283
滥情空心
滥情空心 2020-12-10 06:48

I have a subroutine called debug I use in my code. It basically allows me to see what\'s going on, etc.

sub debug {
    my $message      = shift         


        
相关标签:
5条回答
  • 2020-12-10 07:05

    Just get rid of prototypes altogether:

    sub debug;
    
    debug "Here I am! And the value of foo is $foo";
    debug "I am in subroutine foo", 3;
    
    sub debug {
        # body of debug
    }
    
    0 讨论(0)
  • 2020-12-10 07:05

    You have to declare the same prototype when you define your subroutine:

    sub debug($;$); # prototype/declare
    
    ... meat of the program ...
    
    sub debug($;$) {
        ...
    }
    
    0 讨论(0)
  • 2020-12-10 07:07

    If I am understanding correctly, you want to prototype and predeclare so that you can use the function (prototyped and braceless) within the same file. This is what the subs pragma is for.

    For example, this code works correctly:

    #!/usr/bin/env perl
    
    use strict;
    use warnings;
    
    use subs qw/mysay/;
    
    mysay "Yo";
    mysay "Yo", "Joel";
    
    sub mysay ($;$) {
      my $message = shift;
      my $speaker = shift;
      if (defined $speaker) {
        $message = "$speaker says: " . $message;
      }
      print $message, "\n";
    }
    
    0 讨论(0)
  • 2020-12-10 07:09

    Here's how to do it:

    sub debug;  #Prototype debug subroutine
    
    #Here goes the main program code/
    
    sub debug($;$) {
       #Here goes the debug subroutine code/
    }
    
    0 讨论(0)
  • 2020-12-10 07:19

    The prototype is attached to the coderef and not the name, so when you replace the coderef with the new declaration, you are clearing the prototype. You can avoid having to cross-reference and match prototypes with a helper function:

    sub debug ($;$);
    
    debug 'foo';
    
    use Scalar::Util 'set_prototype';
    sub install {
        my ($name, $code) = @_;
        my $glob = do {no strict 'refs'; \*$name};
        set_prototype \&$code, prototype \&$glob;
        *$glob = $code;
    }
    
    BEGIN {
        install debug => sub {
            print "body of debug: @_\n";
        };
    }
    

    install is just a wrapper around Scalar::Util's set_prototype function, which allows you to change the prototype of a coderef after it is created.

    Prototypes can be very useful, but when using the scalar prototype, always ask yourself if that is really what you intended. Because the ($;$) prototype tells perl "debug is a function that can take one or two arguments, each with scalar context imposed on the call site".

    The bit about context is where people usually get tripped up, because then if you try to do this:

    my @array = qw(one two);
    
    debug @array;
    

    Then @array gets seen in scalar context, and becomes 2. So the call becomes debug 2; rather than debug 'one', 'two'; as you might have expected.

    0 讨论(0)
提交回复
热议问题