rules (?) of parens/brackets usage in perl
Asked Answered
U

2

12

Did some search but couldn't find anything useful. I was wondering if there is a summary table of sort for beginners to learn about the "rules" of using parens/brackets, specifically, the differences among (), [], {}. Unfortunately, in my experience, use strict and use warnings don't tell me if I use the wrong parens.

For example, below are the legit codes (b/c they came from ikegami).

@{"genotype".($i)}
@{$genotype[$i]}
$genotype[$i] = [ split (/:/, $original_line[$i])]
my @genotype = map {[split /:/]} @original_line[6..14]

But are these below also legit ? Often times it's hard enough (for me) to know if it's other parts (logic) of the codes that cause the problem. Sorting through parens to me (a beginner) seems trivial to good coding. Any guide on how to properly use parens will be great.

@{"genotype".[$i]}
@["genotype".($i)]
@("genotype".($i))
@{$genotype($i)}
@[$genotype($i)]
$genotypes[$i] = ( split (/:/, $original_line[$i]))
my @genotype = map ([split /:/]) @original_line[6..14]
Underrate answered 22/4, 2013 at 17:57 Comment(3)
Did you read the references tutorial? perldoc.perl.org/perlreftut.htmlCytology
Start with Perl Intro and then read about Perl data structures.Tilden
Most of these links don't specifically talk about the usage of bracket/parens, unless I missed them in my reading. They provide examples as pertinent to particular usages, but I was hoping to obtain a general view (if existing) first before I go with specifics - a general view as in e.g. functions always with curly brackets or array always with square brackets or reference always with curly brackets. Amon's answer does provide a good summary for a beginner like me. Thanks all.Underrate
A
13

In Perl, brackets, braces and parens all have multiple meanings, but curly braces probably have the most.

  • Parens
    • Sort out precedence 2 * 3 + 4 vs. 2 * (3 + 4).
      • Delimiting argument lists for functions is a subcase of this: join "", 1, 2, 3 vs. join("", 1, 2), 3
      • Surround argument list of method call with arrow operator: $foo->bar(1, 2) (not needed for empty arglist)
    • Force interpretation of the previous bareword as a subroutine call. Compare Foo->new and Foo()->new.
    • Invoke coderefs with arrow operator: $code->()
    • Subroutine prototypes sub foo ($$;$%) { ... }
  • Square Brackets
    • Array subscript operator my @array = 1 .. 5; $array[1]
    • Arrayref literals my $aref = [1 .. 5]
  • Curly braces
    • Blocks (for do, sub, map, grep, conditionals, looping constructs, bare blocks, labeled blocks, ... )
    • Hash subscript operator $hash{foo}
    • Hashref literal my $hashref = { a => 3, b => 2 }
    • Dative block print { $filehandles[5] } "Hello world"
    • Circumfix dereference operators @{ $aref }, %{ $hashref }, ...
    • package blocks package Foo { ... }

… and nearly all characters can be used as delimiters for quote-like operators q//, qq//, qr//, qx//, m//, s///, tr///, y///, leading to interesting stuff like s(foo){bar}g


@{"genotype".($i)} uses curlies for symbolic dereferencing, and parens to (unneccessarily) sort out precedence.

@{$genotype[$i]} uses brackets as array subscript operator, and curlies for dereferencing

$genotype[$i] = [ split (/:/, $original_line[$i])] has various parts: $genotype[$i] and $original_line[$i] use brackets for array subscripting. The = [ ... ] uses brackets to make an anonymous arrayref. The parens in split(/:/, ...) just delimit the argument list for split (sorting out the precedence).

my @genotype = map {[split /:/]} @original_line[6..14] uses brackets as the array subscript operator in @original_line[6..14], and for an anonymous array in [split /:/]. The curlies are used to form a block as first argument to map.

Atheism answered 22/4, 2013 at 18:28 Comment(5)
Parens can also be used as a no-op where an expression is expected (@a = ();, $count = () = f();)Lozier
I like how you didn't claim that parens create lists.Lozier
Curlies are also used to delimit variables in interpolation (e.g. "${foo}bar"). Actually, you can do that outside of the interpolation too (e.g. $a = $foo;) although there's never any reason to do so.Lozier
I come on that post searching in what cases brackets make list and when sort out the precedence. I'm a little afraid because I'm not sure when the brackets make a list of one elem. Strangely not mentioned in that post.Encompass
@MiroslavPopov Parens () don't make lists. Lists depend on list vs. scalar context. However, you do need parens when assigning a list because = has higher precedence than comma. Examples for scalar assignment, no lists are involved: my $x = 1, 2, 3; my $y = (1, 2, 3); say "x=$x y=$y"x=1 y=3. Examples for lists assignment: my @x = 1, 2, 3; my @y = (1, 2, 3); my ($z) = (1, 2, 3); say "x=(@x) y=(@y) z=$z"x=(1) y=(1 2 3) z=1Atheism
L
2

map has two syntaxes

map BLOCK LIST
map EXPR, LIST

In both cases, parens can be used around the args like a normal sub.

map(BLOCK LIST)
map(EXPR, LIST)

One thing of note is that while LIST can return an empty list, it cannot be omitted entirely as you can for subs.


map { [split /:/] } @original_line[6..14]

is an example of map BLOCK LIST, while

map([split /:/])

illegally provides EXPR, but no LIST. Here are acceptable syntaxes:

map({ [split /:/] } @original_line[6..14])
map { [split /:/] } @original_line[6..14]
map([split /:/], @original_line[6..14])
map [split /:/], @original_line[6..14]

If the expression was something like (2+$_)*3, you only have these options:

map({ (2+$_)*3 } ...)
map { (2+$_)*3 } ...
map((2+$_)*3,  ...)

If you remove the parens from that last, you end up with the illegal

map(2+$_)

You can disambiguate using +

map +(2+$_)*3, ...

but it's better to switch to the map BLOCK LIST notation.

Lozier answered 22/4, 2013 at 18:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.