Variables and Types in Perl
Learn about scalars, arrays, hashes, sigils, context, and type conversions in Perl with practical Docker-ready examples
Perl’s approach to variables is unique among programming languages. Instead of declaring a type, you prefix each variable with a sigil—a symbol that tells Perl (and you) what kind of data structure the variable holds. A dollar sign means a single value, an at-sign means a list, a percent sign means a key/value mapping. The sigils are part of the variable’s identity.
Perl is dynamically and weakly typed. Variables do not hold a declared type; scalars can hold a number, a string, or a reference, and Perl will silently convert between strings and numbers as the situation demands. This flexibility is one of the reasons Perl became famous for rapid text processing and system administration scripts.
Even more unusual is Perl’s notion of context. The same expression can produce different results depending on whether it is evaluated in scalar context (expecting a single value) or list context (expecting multiple values). Understanding context is essential to reading and writing idiomatic Perl.
This tutorial walks through scalars, arrays, hashes, undef handling, constants, and the type conversions that happen automatically when Perl sees a string where it expected a number—or the other way around.
Scalars, Arrays, and Hashes
Perl has three fundamental variable types, each with its own sigil. Scalars ($) hold a single value—a number, string, or reference. Arrays (@) hold an ordered list of scalars indexed by integer. Hashes (%) hold an unordered collection of scalar values indexed by string keys.
The my keyword declares a lexically-scoped variable. Combined with use strict, it helps catch typos by requiring every variable to be declared before use.
Create a file named variables.pl:
| |
Notice how $languages[0] uses the $ sigil, not @, even though @languages is an array. The sigil describes what you are accessing, not what the variable was declared as: a single element of an array is a scalar, so it takes $.
Context and Type Coercion
Perl converts between numbers and strings automatically. A string that looks like a number is treated as a number in numeric context; any scalar becomes a string when concatenated or interpolated. This is what “weak typing” means in practice.
Context is the other side of the coin. The same array in scalar context gives its element count; in list context it gives its elements. You rarely force context explicitly—most operators impose a context on their operands—but the scalar keyword is available when you need to be explicit.
Create a file named context_and_coercion.pl:
| |
The string "0.0" is truthy in Perl, even though it looks like zero. Perl’s truthiness rules operate on the literal string form, not a numeric interpretation: only the specific strings "" and "0" are false. This trips up programmers coming from other dynamic languages.
Undef and Constants
Perl’s equivalent of null is undef—a special value that means “no value yet.” Reading an uninitialized variable returns undef, and looking up a missing hash key does too. The defined-or operator // (introduced in Perl 5.10) provides a clean way to supply defaults only when a value is undefined, as opposed to || which also triggers on 0 or empty strings.
For values that should never change, Perl offers several ways to create constants. The use constant pragma creates a true compile-time constant; a lexically-scoped Readonly variable is another option (via CPAN). For simple cases, a my scalar assigned once and never modified works in practice.
Create a file named undef_and_constants.pl:
| |
Note the difference between // and ||: the first line assigns 8080 because $port is undef, but $chosen_host stays as the empty string because "" is defined (just falsy). Using || instead would have replaced the empty string—sometimes desired, sometimes a bug.
Running with Docker
| |
Expected Output
variables.pl:
integer = 42
float = 3.14159
name = Perl
char = P
first language = Perl
third language = Ruby
array size = 4
last index = 3
Perl creator = Larry Wall
Ruby creator = Yukihiro Matsumoto
sum of numbers = 60
context_and_coercion.pl:
"25" + 7 = 32
"25" . 7 = 257
"hello" + 5 = 5
"42 bananas" + 0 = 42
count = 3
joined2 = apple banana cherry
first = apple
second = banana
explicit scalar: 3
falsy: '0'
falsy: '0'
falsy: ''
truthy: 'false'
truthy: '0.0'
truthy: '1'
undef_and_constants.pl:
maybe is undef
chosen_port = 8080
chosen_host = ''
chosen_user = 0
fallback with || = 'local'
PI = 3.14159265
MAX_SIZE = 100
APP_NAME = CodeArchaeology
carol's score = not recorded
alice exists: yes
dave exists: no
Note that variables.pl and context_and_coercion.pl will emit warnings under use warnings for the non-numeric string coercions ("hello" + 5 and "42 bananas" + 0). These warnings go to STDERR, not STDOUT, and do not appear in the output shown above.
Key Concepts
- Sigils identify the access type, not the variable type:
$for a scalar value,@for a list,%for a key/value mapping.$array[0]uses$because one element of an array is a scalar. myanduse strictintroduce lexically-scoped variables and catch undeclared-variable typos. Always use them in modern Perl code.- Dynamic, weak typing: scalars auto-convert between strings and numbers based on the operator.
+forces numeric context;.forces string context. - Context matters: an array in scalar context gives its element count; in list context it gives its elements. Most operators impose context on their operands.
- Falsy values are
undef,0,"0", and""—and nothing else. The string"0.0"is truthy because only the literal string"0"counts as false. - Defined-or (
//) vs logical-or (||)://only triggers when a value is undefined, while||triggers on any falsy value. Use//for default values when0or""are legitimate. undefis the “no value” sentinel: usedefined()to check for it, andexists()to check hash key presence without triggering autovivification.- Constants via
use constantare compile-time and cannot be modified. They integrate cleanly withuse strict.
Comments
Loading comments...
Leave a Comment