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

I have been playing with different styles and data structures, just trying to get a feel for perl better, and what I can do. I have been reading Perl Objects, References and Modules by Randal L. Schwartz. So I have seen what I can do with subroutine references. Now I am a subroutine prototyper by nature. In fact I do two things that seem to frustrate some fellow programers but it seems natural to me. I declare my subroutines before using them and prototype them at the same time. There are many reasons to do this, but a few is to catcht programming errors. The main being:

That said I have had problems with prototypes to anonymous subroutines.

use strict; my $SubRef = sub (\@$){ my $ArrayRef = shift; my $Scalar = shift; foreach my $item (@$ArrayRef){ print "$item"; } print "\n"; print "$Scalar"; print "\n"; }; my @Array = ("This ", "Is ", "A ", "Test ", "."); my $Scalar = "That was a test."; $SubRef->(@Array , $Scalar);

Now this code gives me:

Can't use string ("This ") as an ARRAY ref while "strict refs" in use +at C:\Projects\test.pl line 5.
Now if I change the code like this:
my $SubRef = sub ($$){
and
$SubRef->(\@Array , $Scalar);
And the output is fine. I can even leave it as:
my $SubRef = (\@$){
As long as I change the call to the sub to have the \@ it works. Am I missing something here or doing something silly. I am probably doing something silly but I can't see it. Any pointers or references would be appreciated. Sorry didn't see the pun in that until posted.

Update:
So would it be better to use anonymous arrays and hashes as a general rule of thumb? It seems to me this would minimise confusion in the subs by making the main body of the program ensure that everything already was a ref before you call the sub. But this might just be the mindset for what I am doing. Thank you all for the information.

"No matter where you go, there you are." BB

Replies are listed 'Best First'.
Re: Subroutine References
by blokhead (Monsignor) on Dec 07, 2003 at 22:33 UTC
    I'll give you the obligatory plug to Tom Christiansen's excellent Prototypes in Perl article from perl.com. You seem to be only using prototypes to "use minimal error checking on the values passed to the subroutines" as you say (your other comments only refer to predeclaring subs). Tom's article explains well why prototypes don't really do this for you (or at least do it poorly at the cost of certain usability). Prototypes are cute sometimes to be able to pass references implicitly (a \@ prototype for instance), making your sub look more like a builtin (i.e, push)... but it looks like you understand how references work, so passing them explicitly and foregoing prototypes would probably be no skin off your back. Again, I can't explain it half as well as Tom does, so please read that article!

    More on point to your original question, here's the relevant text from perldoc perlsub:

    The prototype affects only interpretation of new-style calls to the function, where new-style is defined as not using the "&" character. In other words, if you call it like a built-in function, then it behaves like a built- in function. If you call it like an old-fashioned subroutine, then it behaves like an old-fashioned subroutine. It naturally falls out from this rule that prototypes have no influence on subroutine references like \&foo or on indirect subroutine calls like &{$subref} or $subref->().

    blokhead

      I have read both but missed the reference bit because I wasn't using references at the time. Should have reread when I encountered this error. Thank you for that though. But even more importantly it gives me a reason to stop prototyping. I felt I needed to stop doing it after reading the above article but couldn't really say why until this.

      "No matter where you go, there you are." BB
Re: Subroutine References
by ysth (Canon) on Dec 07, 2003 at 22:33 UTC
    Pretty much the exclusive domain of prototypes is to make a perl sub act like a builtin. Once you call it via $subref-> or &subname, you are no longer treating it as a builtin and prototypes are ignored.

    Update: I second the recommendation that you read Tom's article. To make it brief, prototypes in perl5 don't do what prototypes in most other languages do, and weren't designed to. If you assume otherwise, you're in for grief.

Re: Subroutine References
by etcshadow (Priest) on Dec 07, 2003 at 22:34 UTC
    From perldoc perlsub in the first paragraph under prototypes:
    The declaration of the function to be called must be visible at compile time. The prototype affects only the interpretation of new-style calls to the function, where new-style is defined as not using the & character. In other words, if you call it like a builtin function, then it behaves like a builtin function. If you call it like an old-fashioned subroutine, then it behaves like an old-fashioned subroutine. It naturally falls out from this rule that prototypes have no influence on subroutine references like \&foo or on indirect subroutine calls like &{$subref} or $subref->().
    I think that pretty much explains it.

    ------------
    :Wq
    Not an editor command: Wq
Re: Subroutine References
by tcf22 (Priest) on Dec 07, 2003 at 22:35 UTC
    What I think you are asking is why my $SubRef = sub ($$){...}

    Lets you call it with an array ref like

    $SubRef->(\@Array , $Scalar);

    And I believe the answer is that an array ref is actually scalar, so the prototyping allows it whether it is sub(\@$) or sub($$)


    UPDATE: I was wrong. Just ignore me.

    - Tom