Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Subroutine References

by Ninthwave (Chaplain)
on Dec 07, 2003 at 22:21 UTC ( [id://312978]=perlquestion: print w/replies, xml ) Need Help??

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:

  • My variables become pseudo-global because they spill into the subroutine from above. There was some code I was editting recently and I could not figure out where the sub was getting the value from and I had to come through the main programming area to find the variable. To me a sub should be self-contained fully. And declaring them before the program avoids this.
  • By prototyping I can use minimal error checking on the values passed to the subroutines.
  • I prefer to see the definition of the sub before I see the call to the sub. Just habit I hate reading code and than using find to see the sub at the end. When reading code and the subs are at the top I see what each is doing and have a summary in my mind when I see the call
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

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://312978]
Approved by valdez
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others admiring the Monastery: (3)
As of 2024-04-20 14:36 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found