ampersand subroutine

G

Guy

I've seen some code that call user subroutines without the ampersand. I
didn't know you could do that.

"BTW, I went out and bought Learning Perl to help with my Intermediate
Perl."

So I read that you can omit the ampersand if "the compiler sees the
subroutine definition before invocation or..."

But instead of declaring all my subroutines at the begining of my script, or
ensuring they're located ahead of invocation, wouldn't it just be safer and
even easier to always have the ampersand? or are ampersand really a thing of
the past when not absolutely needed?

Guy
 
J

Jürgen Exner

Guy said:
I've seen some code that call user subroutines without the ampersand. I
didn't know you could do that.

It has different semantics, so it depends upon what you want/need.
So I read that you can omit the ampersand if "the compiler sees the
subroutine definition before invocation or..."
But instead of declaring all my subroutines at the begining of my script, or
ensuring they're located ahead of invocation, wouldn't it just be safer and
even easier to always have the ampersand? or are ampersand really a thing of
the past when not absolutely needed?

You got the wrong idea. Actually several wrong ideas.
1: where if not at the beginning of your script do you define your subs?
You don't do that in the middle of the main body, do you?
2: as you wrote correctly the declaration has to be before the
invocation, while the definition of the sub can be anywhere, even
textually after its invocation
3: the ampersand is not "a thing of the past". It modifies the calling
semantic, such that
a) prototypes are overridden
b) @_ is visible to the called sub
(for details see perldoc perlsub).
If you want that semantic (which IMO is somewhat screwy) then use
ampersands. For normal programs it causes too many unwanted
dependencies, so I advise against using them. It is just easier not
having to deal with them.

jue
 
T

Tad J McClellan

Jürgen Exner said:
It has different semantics, so it depends upon what you want/need.


(with a subtext of "you almost never want the semantics that ampersand gives")



Where did you read it?



The above was a rhetorical question, as I recognize that quote
from the Llama book.

You snipped the part after the "or":

if Perl can tell from the syntax that it's a subroutine call

All of my code makes use of that snipped part.



I define my subroutines at the end of my program, after the main code.

I do not declare my subroutines either.

("define" and "declare" mean different things.)

Yet I never use ampersand on subroutine calls.


So how do my programs end up working then?

I make use of the part after the "or"...

.... I always use parenthesis when calling my user-defined subroutines.



Both approaches have "safety" issues.

Using the ampersand may invoke the often unwanted semantics mentioned below.

Using only parenthesis may call a built-in subroutine with the
same name rather than the user-defined subroutine.

You got the wrong idea. Actually several wrong ideas.
1: where if not at the beginning of your script do you define your subs?
You don't do that in the middle of the main body, do you?


I do it at the end.

2: as you wrote correctly the declaration has to be before the
invocation,


.... or you must use parenthesis around the argument list.

while the definition of the sub can be anywhere, even
textually after its invocation
3: the ampersand is not "a thing of the past". It modifies the calling
semantic, such that
a) prototypes are overridden
b) @_ is visible to the called sub
(for details see perldoc perlsub).
If you want that semantic (which IMO is somewhat screwy) then use
ampersands. For normal programs it causes too many unwanted
dependencies, so I advise against using them. It is just easier not
having to deal with them.


Debugging when the ampersand approach is used can be really tricky.

Debugging when the parenthesis approach is used is easy. Just do a

perldoc -f my_func

If it returns docs for my_func(), then choose a different name
for your user-defined subroutine.

So as Jürgen said, it is not a thing of the past.

However, the "when not absolutely needed" part _is_ correct.

The ampersand is absolutely needed if you want the above special
treatment of the sub's argument list or if you insist on using
the same name as a built-in.

It is rare to want or need the arg special treatment, and I do not
recommend reusing the name of a built-in Perl function.


So if you follow a simple rule, you won't have much to worry about:

Never use ampersand on subroutine calls, always use parenthesis
on (user-defined) subroutine calls (but watch out for name collisions)
 
C

ccc31807

Putting the 'main' code at the beginning and the subs at the end is not
a bad idea. It means the script reads top-down, so you get a general
overview of what it does before seeing the detail.

Absolutely! In general, you might find yourself writing 'main' code
that's simply a sequence of function calls with only a few lines of
code, and your functions defined AFTER your program exits, and a
separate section, labled and documented.

Or better yet, if you have a number of user defined functions, in
modules with descriptive names, like a C program with a very short
main function but a number of include files that contain your
functionality.

CC
 
N

News123

i Juergen,

I'm a little surprised by one of Guy's and one of your statements.



Please see my example at the end of the post.
the function is declared after the call and things work fine.

3: the ampersand is not "a thing of the past". It modifies the calling
semantic, such that
a) prototypes are overridden
b) @_ is visible to the called sub

@_ is also visible in my example, but you say the ampersand is needed.
I guess you mean soething different, but I don't understand it.

My example:
----------------
use strict;
use warnings;
require 5.000;
func1(1,2,3);
func2(4,5,6);
exit(0);

# ##############################################################
# now only function declarations (after the "function calls"
# the question is whether I should do this and what damage
# is done if I do it.
#
sub func1 {
print "I am func 1 and my args are <",join("> <",@_),">\n";
func2(@_);
}


sub func2 {
print "I am func 2 and my args are <",join("> <",@_),">\n";
}
 
U

Uri Guttman

N> @_ is also visible in my example, but you say the ampersand is needed.
N> I guess you mean soething different, but I don't understand it.

you don't get the docs. it is not that @_ is 'visible'. when you call a
sub with () you always set @_ to the arg list or empty if no args. when
you call with &foo, @_ is LEFT AS IS and that is seen by the called
sub. that is a major difference and nasty if you don't expect it. so
using () is the proper way to call subs in ALL cases unless you must use
the & semantic (which is very very rarely needed). there is no other
defensible reason to use & style calls in perl.

uri
 
P

Peter J. Holzer

3: the ampersand is not "a thing of the past". It modifies the calling
semantic, such that
a) prototypes are overridden
b) @_ is visible to the called sub

I'd say it is exactly these properties that make & "a thing of the
past". In modern perl-code you don't want to do these things (well,
almost never).

There is one place where you still need the ampersand - if you need to
take a reference to a sub. You cannot write

sub foo {
...
}

my $x = \foo;

you need to write

my $x = \&foo;

(otherwise foo will be called and $x will get a reference to its return
value).

hp
 
U

Uri Guttman

PJH> There is one place where you still need the ampersand - if you
PJH> need to take a reference to a sub.

PJH> my $x = \&foo;

also with magic goto you need the & prefix. and it leaves @_ as is which
is an important part of its semantics of replacing the current sub with
another. we never said & was not needed in perl, it is just not needed
nor generally wanted in directly calling subs. when i see & for sub
calls it raises a red flag and it usually means the rest of the code is
on the poor side.

uri
 
J

Jürgen Exner

News123 said:
I'm a little surprised by one of Guy's and one of your statements.




Please see my example at the end of the post.
the function is declared after the call and things work fine.

That's because (as Tad explained earlier) you are calling it with an
argument list, i.e. with paranthesis. If you omit the paranthesis then
you will get an error about bareword not allowed.
@_ is also visible in my example, but you say the ampersand is needed.
I guess you mean soething different, but I don't understand it.

Uri already explained that part.

jue
 
P

Peter J. Holzer

PJH> There is one place where you still need the ampersand - if you
PJH> need to take a reference to a sub.

PJH> my $x = \&foo;

also with magic goto you need the & prefix. and it leaves @_ as is which
is an important part of its semantics of replacing the current sub with
another.

Yes, magic goto was one of the reasons why I qualified "you don't want
to do that" with "almost never".
we never said & was not needed in perl,

who is "we"? And anyway, I didn't say that you said that, quite the
contrary. To me, Jürgens claim that "& is not a thing of the past"
implied that & *is* regularly needed in Perl for supressing prototypes
and preserving @_. I stronglly disagree with that (and I don't actually
think Jürgen meant that), so I wrote that you usually *don't* want to do
these things.
it is just not needed nor generally wanted in directly calling subs.
when i see & for sub calls it raises a red flag and it usually means
the rest of the code is on the poor side.

I fully agree with that.

hp
 
T

Tad J McClellan

News123 said:
i Juergen,

I'm a little surprised by one of Guy's and one of your statements.




Please see my example at the end of the post.
the function is declared after the call and things work fine.


There *are no* function declarations in your code.

There are only function definitions.

"define" and "declare" mean very different things!

@_ is also visible in my example,


That is because you *pass* its contents to func2.

func1's @_ is NOT visible to func2. func2 has a *different* @_.

but you say the ampersand is needed.
I guess you mean soething different, but I don't understand it.


----------------
#!/usr/bin/perl
use warnings;
use strict;

func1(1,2,3);

sub func1 {
&func2;
}

sub func2 {
print "$_\n" for @_;
}
 
N

News123

Thanks for your explanations Uri and Juergen.


As you said I misunderstood the term 'visible' and I
always called own functions with '()', so never fell
into the problem of calling a sub before its declaration

For 99% of perl code I would give following advise:

Don't use ampersand for calling functions
Don't use function prototypes
Don't declare functions separately before their definition.
Group your function definitions either roughly bottom up at the
beginning of your script or group them all top down at the end of your
script.
In the latter case I'd suggest an explicit exit() statement before the
function definitions in order to signal to a person reading the code,
that no more code outside of function definitions will follow (except of
course for potential BEGIN blocks)

bye
 
B

brian d foy

There is one place where you still need the ampersand - if you need to
take a reference to a sub.

That's why we still talk about the & in Learning Perl. It makes the sub
look more like what people already know about the other variable types.
 
B

brian d foy

Guy said:
I've seen some code that call user subroutines without the ampersand. I
didn't know you could do that.

"BTW, I went out and bought Learning Perl to help with my Intermediate
Perl."

So I read that you can omit the ampersand if "the compiler sees the
subroutine definition before invocation or..."

Remember that Learning Perl purposedly ignores a lot of details so you
can get started as a Perl programmer a lot sooner than you would if you
have to digest all of the Perl documentation.

The leading ampersand on subroutine names is a first-week beginner
thing before you've gone through perlfunc to see what Perl already
defines. Often our students will redefine built-ins (log is a favorite)
during their first couple of days of Perl.
 
A

Andrew DeFaria

body { font: Helvetica, Arial, sans-serif; } p { font: Helvetica, Arial, sans-serif; } ..standout { font-family: verdana, arial, sans-serif; font-size: 12px; color: #993333; line-height: 13px; font-weight: bold; margin-bottom: 10px; } ..code { border-top: 1px solid #ddd; border-left: 1px solid #ddd; border-right: 2px solid #000; border-bottom: 2px solid #000; padding: 10px; margin-top: 5px; margin-left: 5%; margin-right: 5%; background: #ffffea; color: black; -moz-border-radius: 10px; } ..codedark { border-top: 10px solid #03f; border-left: 1px solid #ddd; border-right: 2px solid grey; border-bottom: 2px solid grey; padding: 10px; margin-top: 5px; margin-left: 5%; margin-right: 5%; background: black; color: yellow; -moz-border-radius: 10px; } #code { color: black; font-size: 14px; font-family: courier; padding-left: 5px; } #line-number { color: #804000; font-family: Arial; font-size: 14px; padding-right: 5px; border-right: 1px dotted #804000; } blockquote[type=cite] { padding: 0em .5em .5em .5em !important; border-right: 2px solid blue !important; border-left: 2px solid blue !important; } blockquote[type=cite] blockquote[type=cite] { border-right: 2px solid maroon !important; border-left: 2px solid maroon !important; } blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] { border-right: 2px solid teal !important; border-left: 2px solid teal !important; } blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] { border-right: 2px solid purple !important; border-left: 2px solid purple !important; } blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] { border-right: 2px solid green !important; border-left: 2px solid green !important; } News123 wrote: Don't use function prototypes
I've heard that function prototypes don't always work - yet I find them useful. Where do they fail?
Don't declare functions separately before their definition.
Needed for recursive functions if you use prototypes.
Group your function definitions either roughly bottom up at the beginning of your script or group them all top down at the end of your script.
I fail to find the wisdom in putting all your functions at the bottom and push "main" to the top. IMHO well written scripts usually don't have exciting mains or if they do, they generally are "well worn" and thus usually not the part of the script that you, as a modifier, are generally interested in.
 
U

Uri Guttman

SP> If you're communicating to a person, comments are far clearer:

SP> # End main code body
SP> # Function definitions follow

SP> Use exit() for its intended purpose, explicitly returning an exit code
SP> to the parent process.

i disagree. in my top level programs i always put an explicit exit()
after the main line code ends. comments can lie and there could be left
over code below that would execute that shouldn't. i teach this style
for top level programs:

* a small number of key lexical declarations
* up to about 5 or so top level sub calls (maybe storing results
in lexicals)
* then exit().

if you start getting too many top level calls, refactor some into
another call and move that sub after the exit.

other layout points include putting arg parsing, usage and similar
support subs at the very bottom where they are out of the way. put the
subs in a general top down calling order (need not to be
perfect). higher level subs can be followed immediately but some subs
they call. of course, keep sub sizes reasonably small so you can
understand them quickly.

this makes for an easy to read and understand program.

uri
 
N

Nathan Keel

Uri said:
the >> function definitions in order to signal to a person reading the
code, >> that no more code outside of function definitions will follow

SP> If you're communicating to a person, comments are far clearer:

SP> # End main code body
SP> # Function definitions follow

SP> Use exit() for its intended purpose, explicitly returning an exit
code SP> to the parent process.

i disagree. in my top level programs i always put an explicit exit()
after the main line code ends.

If it's Perl code you're talking about, why not use something better
suited for that, if you might have code/routines/comments that could
create problems? exit() isn't the best method for preventing that
problem, as much as I agree that it's not a bad idea for the same
reasons, exit() isn't what I'd suggest.
 
U

Uri Guttman

NK> If it's Perl code you're talking about, why not use something
NK> better suited for that, if you might have code/routines/comments
NK> that could create problems? exit() isn't the best method for
NK> preventing that problem, as much as I agree that it's not a bad
NK> idea for the same reasons, exit() isn't what I'd suggest.

huh?? use what is better? exit is to exit and also tell the reader than
no more main line code will be executed. it serves a dual purpose. not
much else can do that.

uri
 
A

Andrew DeFaria

body { font: Helvetica, Arial, sans-serif; } p { font: Helvetica, Arial, sans-serif; } ..standout { font-family: verdana, arial, sans-serif; font-size: 12px; color: #993333; line-height: 13px; font-weight: bold; margin-bottom: 10px; } ..code { border-top: 1px solid #ddd; border-left: 1px solid #ddd; border-right: 2px solid #000; border-bottom: 2px solid #000; padding: 10px; margin-top: 5px; margin-left: 5%; margin-right: 5%; background: #ffffea; color: black; -moz-border-radius: 10px; } ..codedark { border-top: 10px solid #03f; border-left: 1px solid #ddd; border-right: 2px solid grey; border-bottom: 2px solid grey; padding: 10px; margin-top: 5px; margin-left: 5%; margin-right: 5%; background: black; color: yellow; -moz-border-radius: 10px; } #code { color: black; font-size: 14px; font-family: courier; padding-left: 5px; } #line-number { color: #804000; font-family: Arial; font-size: 14px; padding-right: 5px; border-right: 1px dotted #804000; } blockquote[type=cite] { padding: 0em .5em .5em .5em !important; border-right: 2px solid blue !important; border-left: 2px solid blue !important; } blockquote[type=cite] blockquote[type=cite] { border-right: 2px solid maroon !important; border-left: 2px solid maroon !important; } blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] { border-right: 2px solid teal !important; border-left: 2px solid teal !important; } blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] { border-right: 2px solid purple !important; border-left: 2px solid purple !important; } blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] blockquote[type=cite] { border-right: 2px solid green !important; border-left: 2px solid green !important; } RedGrittyBrick wrote:
Andrew DeFaria wrote:

I've heard that function prototypes don't always work - yet I find them useful. Where do they fail?

If you haven't already read Tom's article[1], you might find it of interest.

[1] http://groups.google.com/group/comp.lang.perl.modules/msg/84484de5eb01085b

Well I've just read some, but not all - it's quite long. Tom's essential point seems to be "function prototypes are not flawless". Yeah, neither is Perl's current implementation of OO. However I still find both useful.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top