views:

259

answers:

5

I always wonder why I must write

foreach my $x (@arr)

instead of

foreach my $x @arr

What is the purpose of the parentheses here?

+2  A: 

BTW, you can use the expression form of the for without parentheses like this:

s/foo/bar/ foreach @arr; 

or

do { ... } foreach @arr;
eugene y
+2  A: 

Flippant answer: Because that's the way Larry likes it liked it when Perl 5 was created.

More serious answer: It helps to disambiguate between "iterate over @arr, putting each value into $x" (for $x (@arr)) and "iterate over $x and @arr, putting each value into $_" (for ($x, @arr)). And, yes, I realize that the extra comma in the latter version does make disambiguation possible even without the parens, but it's less obvious to a human reader and I expect that relying on that alone would lead to more errors.

Dave Sherohman
That's the way "Larry likes it" is debatable. Why did he change it then to `for @arr -> $item` in Perl 6? It might have just been an evolutionary issue. I do prefer `for my $foo (@array)` over the second form though, for clarity.
szbalint
Are you sure *he* changed it? Perl 6 is written by more than one person.
vol7ron
+6  A: 

I can only think of one concrete reason for it. The following code is valid:

for ($foo) {
    $_++
}

If you were to change that to

for $foo {
    $_++
}

Then you would really be saying

for $foo{$_++}

(i.e. a hash lookup). Perl 6 gets around this issue by changing the way whitespace works with variables (you can't say %foo <bar> and have it mean the same thing as %foo<bar>).

Chas. Owens
`$foo != @foo != %foo`
vol7ron
@vol7ron So you would rather have special syntax because it is an array or a hash?
Chas. Owens
Your example is at best using an array ref, not an array, which is how the question was asked. If David implied something else, he should have taken the time to specify.
vol7ron
@vol7ron I have no idea what you are talking about. My example clearly uses a normal scalar (see the `++`). It shows why parentheses are necessary to prevent confusing the parser. It could just as easily have been `for (@a, $h{a}, $foo) {}` and `for @a, $h{a}, $foo {}`.
Chas. Owens
Exactly, you're using a scalar, his question uses an **array**. What don't you get? Scalar != Array.
vol7ron
@vol7ron The question isn't about arrays, it is about **for** and why its syntax works the way it does in Perl 5. But since you want to be pig headed about this, `for @foo { $_++ }` has the same problem, except now it thinks `@foo{$_++}` is a hash slice on `%foo`. Are you happier?
Chas. Owens
Nope, as stated, if the asker implied something else, he should have taken the time to specify. It was a poor question. -- Furthermore, your example is incorrect. I don't see how you magically get past perl compilation errors: `Scalar value @foo {$_++} better written as $foo {$_++}`, as far as Perl 5.10.1 is concerned.
vol7ron
@vol7ron This is a speculative question about why the syntax works the way it does. I demonstrated a reason why it couldn't work the way David wanted **even if we were to change the syntax of for**. The question is *What is the purpose of the parentheses here?*, the answer, at least in part, is that `perl` needs the parentheses or it will take the `for`'s block as a hash lookup. To get a `for` that doesn't need parentheses we would need whitespace between a name and the lookup operator to be meaningful (as in Perl 6). This means p5p can't remove them in Perl 5.14+ without breaking other code.
Chas. Owens
@vol7ron Oh, and `Scalar value @foo {$_++} better written as $foo {$_++}` is a warning not an error. It is a warning because if there is only one item then chances are good the user meant to type `$foo {$_++}` which puts the lookup in scalar context and hash slices put their lookup in list context which can have strange side effects due to [`wantarray`](http://perldoc.perl.org/fucntions/wantarray.html). Examine [`this code`](http://codepad.org/oJ7GfdZk).
Chas. Owens
Perhaps you could tell me what I'm doing wrong then. What you've listed is different syntax, due to how Perl operates. As another person stated you can do `{...} foreach @arr`, but not `foreach @arr {...}`. See:[http://codepad.org/uqk918jU] - it tries to read the array as a hash, which is similar to what you said above, but still an error because it's an **array**, which is what the asker listed in the question. If the asker did not mean that he should have used something more ambiguous eg `<somevar>` -- BTW the beard is sweet.
vol7ron
@vol7ron You cannot say `for @arr {}`. It is not allowed by the current syntax and cannot be allowed in Perl 5 for the reason I stated (`perl` sees `@arr {}` as a hash slice on `%arr`. No parentheses are required in the statement modifier version because `perl` can't be confused by the similarity of blocks and hash lookup operators if there is no block to confuse it. At no point have I said that `for @a {}` is valid code, I am explicitly saying it isn't valid code and cannot be valid code in a latter version of Perl 5 because it will be misunderstood by `perl`.
Chas. Owens
You are right, but your reasoning is wrong. The hash slice is what occurs because perl is trying to make sense of your code, which isn't written correct to syntax. If you used the array, instead of a scalar, you would have seen that it would have generated and error and not a warning - which is the answer: because it's invalid syntax.
vol7ron
My reasoning isn't wrong. Your belief that I am saying that the code is valid is wrong. The parentheses are currently required. My statement is that they can't be removed in Perl 5.14 or later because if they were then `perl` would become confused (due to the way whitespace between a hash and its index operator). To make it work Perl 5 would have to treat whitespace the same way Perl 6 does (and p5p is highly unlikely do that for backward compatibility reasons).
Chas. Owens
A: 

Perl has two types of functions - one works in scalar context and another works in list context.'Foreach' works in list context so parentheses indicate the its context.

like assume a array:

@a = (1,2,3);

So we can write -

foreach my $x (@a)

OR

foreach my $x (1,2,3)
Divya Saxena
I don't understand why this was downvoted? It's correct. Anyone who's ever tried `foreach my $foo @bar` knows it would'nt work, but `foreach my $foo (@bar)` would.
vol7ron
A: 

David B,

In this context they should be equivalent, however many times parentheses either change the order of operation in which something is performed, or the type of variable returned (a listing). Different functions may handle lists vs arrays/hashes differently.

Order of Operation

During a foreach loop, it's typical to sort a listing:
foreach my $key (sort keys %hash) { ... }

This could also be written as:
foreach my $key (sort(keys(%hash))) { ... }

Lists

On the other hand, you should look at the difference between a list, array, and hash. Lists are generally the base type, where hash/arrays have additional functions/abilities. Certain functions will only operate on lists, but not their scalar counterpart.


Addendum:

I think I should also add, as Randal Schwartz (co-author of the first Camel book) has pointed out in previous citings, that the "for" loop is from C and the "foreach" loop is from Csh. What is inside the parentheses is used to determine which loop is used by perl. The for/foreach can be used interchangeably only because perl examines the contents in the () and then determines which construct to use.

vol7ron