•Re: Surpised by foreach iterator limitation
by merlyn (Sage) on Apr 08, 2003 at 04:12 UTC
|
There are a few places in Perl where you have to use a "simple scalar variable". The iterator binding for a foreach loop is one. The variable of an indirect filehandle read or write is another, as is the indirect object of indirect object syntax, or the expression for which you don't need braces on a dereferencing operation.
It's a consistent notion, but not always common-sense, as evidenced by your (thankfully categorically rare) post.
-- Randal L. Schwartz, Perl hacker
Be sure to read my standard disclaimer if this is a reply. | [reply] |
|
It's a consistent notion, but not always common-sense, as evidenced by your (thankfully categorically rare) post.
I am curious about the (thankfully categorically rare) portion of your comment. The impression it leaves me with is that you think this a bad idea.
While I agree it's very rare and not very useful in day to day use, it fits with the DWIM expectation which in my mind would certainly not be a bad thing.
-Lee
"To be civilized is to deny one's nature."
| [reply] |
|
Bah. I knew that was going to be misinterpreted, but I got lazy.
What I'm saying is that most people don't seem to leap this direction, so we really don't see many posts wondering why it's only a simple scalar.
I tell ya, with all the places I look, I don't see it being questioned very often.
Maybe that's because we do a good job of describing it in the llama, so only non-llama-ites make that leap. {grin}
-- Randal L. Schwartz, Perl hacker
Be sure to read my standard disclaimer if this is a reply.
| [reply] |
|
Re: Surpised by foreach iterator limitation
by graff (Chancellor) on Apr 08, 2003 at 03:19 UTC
|
I see your motivation, and I get the train of thought that led to your initial assumption -- a hash element is an lvalue, and there's an intuitive sense that a loop variable is being used as an lvalue -- elements of the list are being assigned to it on each iteration.
But that intuitive sense seems to be wrong in a subtle way. Many of us have relied on the documented behavior that results in things like:
my @array = qw/1 2 3 4/;
foreach my $elem ( @array ) {
$elem *= 5;
}
print join " ",@array,$/;
__OUTPUT__
5 10 15 20
As pointed out by "perldoc perlsyn": 'the "foreach" loop index variable is an implicit alias for each item in the list that you're looping over.' Another passage from perlsyn, very close afterwards, points out: '"foreach" probably won't do what you expect if VAR is a tied or other special variable. Don't do that...'
Next, we'd have to look closely at how perl stores variables internally (The Damian's excellent book "Object Oriented Perl" has one of the nicest explanations), and try to work out how different a hash element is from a normal scalar. Well, it's late, and I won't try that just now... The point is that the loop variable is not being used as an lvalue -- it's something else with special properties.
update:
Regarding perl implementation issues, I would suppose that the compiler has a very rigid sense of for-loop syntax: the thing after "for" (or "foreach") must be a scalar; if there's a curly brace after that, it probably interprets this as the start of a block (not a hash index), and reports the syntax error because there's no list being provided for the iteration. Of course, the error is reported if you're using an array element (square-brackets) as well. | [reply] [d/l] |
|
It is not different in such a way as to prevent a suitable implementation from functioning. Yes, it would require a little bit of magic, but no more than the magic already provided by local(). Where there is a will, ... This is Perl people... :-)
| [reply] |
|
I just assumed it would hv_fetch() with lval set. I haven't revisited the source yet but I suspect it's a grammer issue.
-Lee
"To be civilized is to deny one's nature."
| [reply] |
Re: Surpised by foreach iterator limitation
by MarkM (Curate) on Apr 08, 2003 at 03:09 UTC
|
Before around perl 5.004, even "my" was not recognized as a means to qualify the iterator variable as having a new lexical scope.
Most things Perl are defined by their actual implementation, and formed via a relaxed but somewhat controlled sort of evolution. In this case, no, I was not surprised. Most likely, because years ago, I tried it, and realized that it did not work... Thankfully, some good people have worked on making syntax such as "EXPR foreach 1 .. 10" work as I had originally expected. So there is hope yet, if you mention this 'inconsistency' to the right person.
| [reply] |
|
"Before around perl 5.004, even "my" was not recognized as a means..."
<confession>Didn't know that. OTOH, I don't think I was using my or strict or warnings back then.</confession>
-Lee
"To be civilized is to deny one's nature."
| [reply] |
Re: Surpised by foreach iterator limitation
by demerphq (Chancellor) on Apr 08, 2003 at 20:47 UTC
|
foreach my $foo qw(bar baz) { print $foo,$/ }
:-)
---
demerphq
<Elian> And I do take a kind of perverse pleasure in having an OO assembly language...
• Update:
*Sigh* apparently people have missed the point here. The qw is special cased so you dont have to write
foreach my $foo (qw(bar baz)) { }
Foo on you people who thought I was being sarcastic!
| [reply] [d/l] [select] |
|
| [reply] |
|
++demerphq!
I just read your update and now I can see what you mean. I've been using that syntax for some time and never even noticed the missing parentheses. So I set out to see if there are any other operators that would work in this situation without outer parentheses. So far I haven't found anything besides the qw// operator.
foreach is expecting an operator that returns a natural list, generally the list operator: (list). qw// works because it is an operator that returns a list at compile time!
Am I missing any other operators that behave the same way?
| [reply] [d/l] [select] |
|
What is so odd about that?
foreach loops over a normal list value. qw returns a normal list. The last line of a block doesn't require a semicolon. It looks quite normal to me.
Unless of course you mean... foo bar baz. :-)
| [reply] |
|
Odd indeed.
-Lee
"To be civilized is to deny one's nature."
| [reply] |
Re: Surpised by foreach iterator limitation
by pg (Canon) on Apr 08, 2003 at 03:00 UTC
|
| [reply] [d/l] [select] |
|
Umm.. I wasn't attempting to iterate through a hash. I was trying to extend a validation function that takes a hash as it's argument to accept multiple values in the laziest way possible. $hash{key} is a scalar variable and can be localized, so I assumed it could be used any place a scalar could which was the point of the post.
-Lee
"To be civilized is to deny one's nature."
| [reply] |
|
Okay, now I see, however, $hash{key} is even not a valid name for a scalar variable.br>
Be careful about this subtle difference: $hash{key} is the valid syntax to point to a hash element, which is a scalar, but it is not the valid syntax to name a scalar.
| [reply] |
|
|
|
|
|
I certainly wasn't suggesting that $hash{key} be a valid scalar name. I simply and mistakenly thought that any lvalue would work in the iterator position.
-Lee
"To be civilized is to deny one's nature."
| [reply] |
|
Seriously, what you suggested here makes sense to me, but I think it is just the syntax, and the parser requires a valid variable name here, (or if it is missing, $_ is assumed).
| [reply] |
Re: Surpised by foreach iterator limitation
by diotalevi (Canon) on Apr 08, 2003 at 03:43 UTC
|
I don't even understand what that snippet of code means. Do you mean that the $hash{ 'key' } variable should be aliased to each of the loop's variables? Or is 'key' supposed to be special somehow in that the iterated value forms the key to the hash? I just can't see how this construction makes sense. Explain it to me - what on earth does it mean?
| [reply] [d/l] |
|
I thought the last paragraph of my post made it clear but perhaps not. I had an involved sub (actually subroutine generator) for validating data. It takes as it's argument a hash. The sub references this in may places. I wanted to refactor it to take multiple arguments for each call. Currently it expects one piece of data. I figured the easiest way and least likely way to intruduce bugs would be to wrap the code in a loop. For example
sub example { # Expects argument data that is a single value
my %p = (@_); #
return if $p{required} && !$p{data};
Do stuff that references $p{data}...
return 1; # OK
}
my $value = 10;
if ( example(data=>$value, minval=>5, maxval=>10){
print "$value is OK!\n";
}else{
die "$value is naughty!";
}
Now let's say I want to extended it to take multiple values
I thought the easiest way would be to do this.
sub example {
my %p = (@_); #
my @data = UNIVERSAL::isa($p{data},'ARRAY') ? @{$p{data}} : ($p{
+data});
foreach $p{data} (@data){
return if $p{required} && !$p{data};
Do stuff that references $p{data}...
}
return 1; # OK
}
It did not work.
This can be solved in a million simple ways such as using a lexical for the iterator and simply$hash{key} = $iterator_variable as the first statement in the loop.) and I am not looking for a fix. I was simply suprised the Perl could not parse this.
-Lee
"To be civilized is to deny one's nature." | [reply] [d/l] |
|
Explain to me why this wouldn't work:
sub exampl {
my %p = @_;
my @data = UNIVESAL::isa($p{data}, 'ARRAY')
? @{$p{data}}
: ( $p{data} );
foreach my $datum (@data)
{
return if $p{required} && !$datum;
# Do stuff that references $datum
}
return 1; # Everything is OK
}
The point here is that you're stuck in the mode of "I have to reference things the same way". Much better is to say "I have an array of stuff. Let's work with that array." Remember - You used to call it $p{data} because it was a member of that hash. Now, it's not. So, don't call it that. Embrace the refactoring goodness.
------ We are the carpenters and bricklayers of the Information Age. Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement. Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified. | [reply] [d/l] |
|
Re: Surpised by foreach iterator limitation
by gmpassos (Priest) on Apr 08, 2003 at 19:34 UTC
|
| [reply] |