Perl Part I · Module 10 · Subroutines and Arguments
Defining and Calling a Subroutine
A subroutine is a piece of work with a name, and in Perl it needs almost no ceremony: the keyword sub, a name, and a block. There is no parameter list in the definition and no return type, which makes the declaration shorter than in most languages and moves two decisions into the body that other languages make for you. Perl also scans the whole file for definitions before running anything, so a subroutine can be called from above where it is written — which is why Perl scripts conventionally put the main flow at the top and the helpers underneath. There are two ways to write a call, they look like minor variants of each other, and one of them quietly hands the called subroutine a completely different set of arguments.
Foundation14 min readPerlPart ISubroutines
Part I · Module 10 · Chapter 10.1 · Defining and Calling a Subroutine
1. The Shape, and Why Order Does Not Matter
use strict;
use warnings;
# the call comes BEFORE the definition, and that is fine
print greet("alu"), "\n";
sub greet {
my ($name) = @_;
return "hello $name";
}hello aluThe call is on line 5 and the definition starts on line 7. Perl compiles the whole file before executing any of it, so by the time line 5 runs, greet exists. Chapter 1.5 established that two-phase behaviour; this is the most useful consequence of it.
That is why the conventional layout of a Perl script is the opposite of what a C programmer expects:
#!/usr/bin/env perl
use strict;
use warnings;
# --- main flow, readable top to bottom
my @rows = parse_report($path);
my @failing = select_failing(@rows);
print_summary(@failing);
# --- helpers below
sub parse_report { ... }
sub select_failing { ... }
sub print_summary { ... }A reader sees what the script does in the first few lines and descends into detail only if they need it. No forward declarations are required, and there is no header file.
The declaration itself has three parts and no more:
| Part | Notes |
|---|---|
sub | the keyword |
NAME | no sigil; greet, not $greet |
{ ... } | the body — braces are mandatory, as everywhere |
There is no parameter list. Perl does not let you name parameters in the definition — the arguments arrive in an array called @_ and you name them yourself on the first line, which is Chapter 10.2's and Chapter 10.3's subject. (Newer Perl has signatures, which do let you name them; Chapter 10.11 covers them and why they are not yet the default.)
2. What a Subroutine Gives Back
use strict;
use warnings;
sub explicit { my ($a, $b) = @_; return $a + $b }
sub implicit { my ($a, $b) = @_; $a + $b }
printf "explicit return : %d\n", explicit(2, 3);
printf "implicit return : %d\n", implicit(2, 3);explicit return : 5
implicit return : 5A subroutine returns the value of its last evaluated expression, whether or not you write return.
That is convenient in a one-line helper and a liability everywhere else:
- The last expression may not be the one you think. A body ending in a
forloop, anifwhose branches assign, or aprintreturns whatever that construct evaluates to —printreturns1on success, so a subroutine ending inprintreturns1and looks like it succeeded by design. - It is invisible when the body changes. Adding a debug
printat the end of a subroutine that relied on an implicit return silently changes its return value.
Write return explicitly. The one place the implicit form is genuinely fine is a short expression-only helper where the whole body is the value:
sub mean { my $n = @_ or return; my $s = 0; $s += $_ for @_; $s / $n }Even there, return costs six characters and removes the question. Chapter 10.6 covers what return does in each calling context, which is a separate and larger matter.
3. Two Ways to Call, and They Are Not the Same
use strict;
use warnings;
sub inner { return "inner saw " . scalar(@_) . " arg(s)" }
sub with_parens { return inner() }
sub without_parens { return &inner }
print with_parens("x", "y", "z"), "\n";
print without_parens("x", "y", "z"), "\n";inner saw 0 arg(s)
inner saw 3 arg(s)Read that twice. Both outer subroutines were called with the same three arguments. The one that called inner() passed none. The one that called &inner passed all three.
4. Calling Without Parentheses at All
print greet("alu"), "\n"; # with parentheses
print greet "alu", "\n"; # without — and now the "\n" is an argument tooA subroutine Perl has already seen can be called without parentheses, like a builtin. That is how print, push and open are called, and it reads well for a subroutine that genuinely behaves like a command.
It is also where the arguments stop being obvious. In the second line above, "\n" becomes a second argument to greet rather than a second argument to print — exactly the precedence problem Chapter 8.4 §5 measured for print (...).
Use parentheses. The exception is a subroutine designed as a command and called with one clear argument, where the convention is already established in the file. Even then, parentheses are never wrong.
Note the ordering dependency: calling without parentheses only works if Perl has already seen the definition at that point in the file. Above the definition it does not fail cleanly — it is reinterpreted. Measured:
use strict;
use warnings;
print greet "alu";
sub greet { return "hi @_" }Unquoted string "greet" may clash with future reserved word at noparen-above.pl line 4.
print() on unopened filehandle greet at noparen-above.pl line 4.0Perl read greet as a filehandle name, because print FILEHANDLE LIST is valid syntax and at that point in the file greet is just a bareword. Nothing was printed, two warnings appeared, and the script exited 0.
So the parenthesised form is not merely tidier — it keeps §1's order-independence intact, and it cannot be mistaken for a filehandle. greet("alu") above the definition works exactly as expected.
5. When a Subroutine Does Not Exist
use strict;
use warnings;
nosuch();Undefined subroutine &main::nosuch called at undefined-sub.pl line 4.255That is a runtime error. perl -c reports syntax OK on this file, because a bare nosuch() is syntactically a valid subroutine call — Perl cannot know at compile time whether something will define it first.
This is now the third runtime-only failure in this curriculum, after Chapter 9.4's last in a do block and Chapter 9.6's misspelled label. All three share the shape: syntactically valid, semantically wrong, and discovered only when control arrives. A misspelled subroutine name on an error path behaves exactly like those.
use strict does not help here either — strict subs governs bareword usage, not calls with parentheses. The defences are the ordinary ones: exercise the error paths, and keep the set of subroutines small enough to know.
6. Redefining a Subroutine
use strict;
use warnings;
sub dup { return 1 }
sub dup { return 2 }
print "dup() = ", dup(), "\n";dup() = 2Subroutine dup redefined at redefine.pl line 5.0The second definition wins, Perl warns, and the script succeeds. That is a warning rather than an error because redefining a subroutine is sometimes deliberate — overriding a function for a test, or installing a platform-specific version.
Where it matters is accidental duplication. Two helpers with the same name in a 900-line script, perhaps added by different people, silently resolve to whichever appears later — and the one that is never called is the one people read when debugging. Subroutine ... redefined is worth treating as an error in review even though Perl treats it as a warning.
Note it is a compile-time warning, so unlike §5 it does appear from perl -c.
7. Why This Matters in Engineering Work
Order-independence shapes the file. Main flow first, helpers below, no declarations needed. A reader can understand what a 600-line parsing script does from its first dozen lines, which is the single biggest readability win available in a Perl script.
The &inner form is a real bug in inherited code. A helper that receives its caller's arguments instead of none produces plausible-looking wrong behaviour, and nothing at the call site hints at it. When reading old Perl, every &name without parentheses is worth checking.
The implicit return is a maintenance hazard rather than a bug. It works until someone appends a line to the body.
And a duplicate definition is a review item. Perl's warning is the only thing that will tell you, and only if anyone is reading STDERR.
8. Common Mistakes
&inner with no parentheses. It passes the caller's @_, not nothing.
Relying on the implicit return. The last expression may not be what you meant, and appending a line changes it.
A body ending in print. It returns 1, which looks like deliberate success.
Calling without parentheses above the definition. Inside a print, Perl reads the name as a filehandle — two warnings and exit 0, nothing printed.
Calling without parentheses with more than one argument. The later arguments may bind to the wrong thing.
Assuming an undefined subroutine is caught at compile time. It is a runtime error, and perl -c passes.
Ignoring Subroutine ... redefined. The later definition silently wins.
Writing $greet for the subroutine greet. A subroutine name takes no sigil; \&greet is how you get a reference.
9. Exercise
Exercise 1 — order. Write a script that calls a subroutine on line 5 and defines it on line 7. Confirm it runs. Then move the call above use strict and record whether that still works.
Exercise 2 — the house layout. Take any three-step task and write it as a main flow of three calls at the top with three helper definitions below. Confirm no forward declaration was needed.
Exercise 3 — implicit return. Write two subroutines that add their arguments, one with return and one without. Confirm they agree. Then append print "done\n"; to the end of the implicit one and record what it now returns.
Exercise 4 — the ampersand. Reproduce §3 exactly. Record both output lines. Then explain in one sentence why the two differ even though both outer subs were called identically.
Exercise 5 — the four call forms. For a subroutine that prints scalar(@_), call it four ways from inside another subroutine that was itself given three arguments: inner(), inner(@args), &inner(@args), &inner. Record all four counts.
Exercise 6 — no parentheses. Call a one-argument subroutine as greet "alu", "\n"; inside a print. Record what the subroutine actually received. Then move the call above the definition and record the error.
Exercise 7 — undefined. Call a subroutine that does not exist. Record the runtime error and exit status, then run perl -c on the same file and record its output and exit status.
Exercise 8 — redefinition. Define the same subroutine twice with different bodies. Record which one runs, the warning, and the exit status. Then confirm perl -c also reports the warning.
10. Summary
sub NAME { ... }defines;NAME()calls. No sigil on the name, no parameter list, no return type.- Perl compiles the whole file first, so order does not matter — a call may precede its definition. That is why the main flow goes at the top and helpers below.
- A subroutine returns its last evaluated expression if you write no
return. Writereturnanyway; a body ending inprintreturns1. &innerwith no parentheses passes the caller's current@_— measured, three arguments forwarded whereinner()passed none. Never write it; use\&inneronly for a reference.- Calling without parentheses works only after Perl has seen the definition. Before it,
print greet "alu"readsgreetas a filehandle —print() on unopened filehandle greet, nothing printed, exit 0. Later arguments can also bind to the wrong thing. Use parentheses. - An undefined subroutine is a runtime error —
Undefined subroutine &main::nosuch called, exit 255 — andperl -cpasses. - Redefining warns at compile time and the later definition wins, with exit 0. Treat the warning as an error in review.
Chapter 10.2 covers where the arguments actually went: a single flat array called @_, with no names and no count check.
Where this fits
Part of the Perl curriculum.
