Comma operators#

Two operators, both spelled with a comma — one of them spelled ”fat comma“ with =>. They are syntactically the same in most positions but differ on the left-hand-side bareword rule.

Operator

Reads as

What it does

,

comma

list separator (in list ctx); discard-and-yield-right (in scalar ctx)

=>

fat comma

same as ,, plus auto-quotes a bareword on the left

In list context — building lists#

In list context the comma is the list-element separator:

my @items = (1, 2, 3, 4);                  # 4-element list
my @flat  = (1, 2, (3, 4), 5);             # (1,2,3,4,5) — lists flatten
my @kv    = (a => 1, b => 2);              # 4-element list: a, 1, b, 2
my %h     = (a => 1, b => 2);              # hash from key-value pairs

Lists in Perl are flat — there is no nested-list value. A list embedded in another list disappears: its elements simply become elements of the outer list. To get nested structure you need references (see the References tutorial):

my @flat   = (1, 2, (3, 4), 5);            # (1,2,3,4,5) — 5 elements
my @nested = (1, 2, [3, 4], 5);            # (1, 2, ARRAYREF, 5) — 4 elements

In scalar context — comma is ”discard, then return right“#

When a comma expression is forced into scalar context — by an assignment to a scalar, by scalar(...), by being the condition of an if — it evaluates each operand left-to-right for side-effects, then yields the value of the rightmost operand:

my $x = (1, 2, 3);                          # $x = 3 — but warn under
                                            # `use warnings`: "Useless use of
                                            # a constant in void context"
                                            # for 1 and 2

my $r = (do_a(), do_b(), final_value());    # runs all three, returns
                                            # the last value

This usage is rare in modern Perl — the C-style for(init, init; cond; step, step) idiom is the main place you encounter it (and even there, parens around the comma sub-expression are advisable).

=> — the fat comma#

=> does the same thing as , plus it auto-quotes the identifier-shaped bareword on its left:

my %h = (
    name  => "John",                        # 'name'  auto-quoted
    age   => 30,
    "key with spaces" => "...",             # quote required for non-bareword
);

# Equivalent without =>, requiring explicit quoting:
my %h = (
    'name', "John",
    'age',  30,
    'key with spaces', '...',
);

The auto-quote applies only when the left side is a syntactically valid bareword identifier — letters, digits, underscores, starting with a letter or underscore. Other shapes are not auto-quoted:

( name      => 1 )           # 'name' auto-quoted — fine
( "name"    => 1 )           # already a string — fine
( $variable => 1 )           # $variable evaluated — fine
( 0+1       => 1 )           # numeric expression — fine
( -name     => 1 )           # WRONG — looks like negative bareword;
                             # parses as -('name') which is the
                             # numeric negation of a string. Quote it.
( CONST     => 1 )           # 'CONST' auto-quoted — does NOT call
                             # the constant CONST!
( CONST()   => 1 )           # explicit empty parens — calls CONST

The interaction with constants is the most common surprise — see also the subscript page on hash key autoquoting, which has the same pattern.

Common idioms#

# Function arguments — the comma is just the argument separator
some_function($arg1, $arg2, $arg3);

# Hash construction — fat-comma communicates "this is a key"
my %config = (
    host => 'localhost',
    port => 8080,
    user => $ENV{USER},
);

# List literal — interchangeable
my @months = (qw/Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec/);

# Trailing comma — allowed and idiomatic for diff-friendly multi-line literals
my @list = (
    "first",
    "second",
    "third",       # trailing comma is fine
);

The trailing comma is intentional: it lets you append, remove, or reorder list elements without touching surrounding lines, which shows up as cleaner diffs in version control.

Precedence#

, and => sit at row 20 — looser than assignment, tighter only than the word-form logicals (and/or/not/xor) and list operators in their right-side position. This is why a list of assignments works:

my $a = 1, my $b = 2;          # WRONG: parses as (my $a = 1), my $b = 2
                               # — comma at outer level, not list assignment.
                               # $a is 1, $b is 2, but the warning is loud.

my ($a, $b) = (1, 2);          # the right way: list assignment

See also#

  • Assignment — list assignment relies on the comma’s role in list context.

  • Subscript$h{name} autoquoting, the parallel case to name => ....

  • use constant — the bareword/constant collision is the canonical fat-comma gotcha.

  • Context — the list-vs-scalar story behind why , means two different things.