Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug in magic locals vs block loops? #1101

Closed
p5pRT opened this issue Jan 28, 2000 · 7 comments
Closed

Bug in magic locals vs block loops? #1101

p5pRT opened this issue Jan 28, 2000 · 7 comments

Comments

@p5pRT
Copy link

p5pRT commented Jan 28, 2000

Migrated from rt.perl.org#2055 (status was 'resolved')

Searchable as RT2055$

@p5pRT
Copy link
Author

p5pRT commented Jan 28, 2000

From Tim_Peters@Dragonsys.com

  it don't with block while
  it works with stmt while
  it don't with block until
  it works with stmt until
  it works with block if
  it works with stmt if

under

  $ perl -v
  This is perl, version 5.005_03 built for i386-linux

I understand that $1 etc are magically local to blocks. However, the
regexp searches and the references to $1 here are all in the same
block. Besides, if this were a legitimate block-related difference,
I'd expect the block forms of "while" and "if" to both succeed or both
fail.

Bug or (incomprehensible <wink>) feature?

looks-like-a-bug-to-me-ly y'rs - tim

$var = "it works or it don't";

$var =~ /(don't)/; # set $1 to "don't"
while ($var !~ /(works)/) {
  die "oops!"; # shouldn't get here ("works" should be found)
}
print "it $1 with block while\n";

$var =~ /(don't)/;
die "oops!" while $var !~ /(works)/;
print "it $1 with stmt while\n";

$var =~ /(don't)/;
until ($var =~ /(works)/) {
  die "oops!";
}
print "it $1 with block until\n";

$var =~ /(don't)/;
die "oops!" until $var =~ /(works)/;
print "it $1 with stmt until\n";

$var =~ /(don't)/;
if ($var !~ /(works)/) {
  die "oops!";
}
print "it $1 with block if\n";

$var =~ /(don't)/;
die "oops!" if $var !~ /(works)/;
print "it $1 with stmt if\n";

@p5pRT
Copy link
Author

p5pRT commented Jan 28, 2000

From @TimToady

Tim_Peters@​Dragonsys.com writes​:
: The attached prints (note "block while" and "block until")​:
:
: it don't with block while
: it works with stmt while
: it don't with block until
: it works with stmt until
: it works with block if
: it works with stmt if
:
: under
:
: $ perl -v
: This is perl, version 5.005_03 built for i386-linux
:
: I understand that $1 etc are magically local to blocks. However, the
: regexp searches and the references to $1 here are all in the same
: block. Besides, if this were a legitimate block-related difference,
: I'd expect the block forms of "while" and "if" to both succeed or both
: fail.
:
: Bug or (incomprehensible <wink>) feature?

Not that Perl doesn't have its share of incomprehensible features, but
I think this one's a bit of buglette too. Especially considering that
it works "right" in Perl 4.

On the other hand, since the buglette is related to the optimization of
not saving and restoring the pattern match context around every loop
iteration, we might be slow to fix it, if we can't figure a decent way
to do it. Fact is that almost nobody ever writes loop conditions with
!, and the buglette won't show up with = because then the pattern
doesn't match on the last iteration, and $1 wouldn't be set anyway.

Plus nowadays there's a bit of a magical lexical scope around entire
while loops and if statements as well. (Not that your buglette is
lexical, it's dynamic.) But anyway, if you write​:

  $wink = "y'rs\n";
  if (my $wink = "wink-ly ") {
  print $wink;
  }
  print "$wink";

You'll find that it prints "wink-ly y'rs", despite the fact that the
my is not within a syntactic block. I suspect that's a feature.
Your buglette is a bit less of a feature, I'd say.

Mind, I'm not promising we won't fix it. I don't make promises like that. :-)

: looks-like-a-bug-to-me-ly y'rs - tim

Nice to hear from you after your long sojourn in snake-strewn lands!

Larry

@p5pRT
Copy link
Author

p5pRT commented Jan 28, 2000

From @tamias

On Fri, Jan 28, 2000 at 06​:10​:28PM -0800, Larry Wall wrote​:

Fact is that almost nobody ever writes loop conditions with
!, and the buglette won't show up with = because then the pattern
doesn't match on the last iteration, and $1 wouldn't be set anyway.

Coincidentally, I happened to stumble across this quirk earlier today while
commenting on a script on another list. In this case, it was roughly​:

until ($line =~ /regex/) {
  $line = <>;
}
if ($line =~ /regex/) {
  print $&;
}

This could have been simplified to​:

until ($line =~ /regex/) {
  $line = <>;
}
print $&;

were it not for this behavior. And no !~ in the loop conditional, either.
:)

Ronald

@p5pRT
Copy link
Author

p5pRT commented Jan 29, 2000

From [Unknown Contact. See original ticket]

[Larry Wall graciously allows]

Not that Perl doesn't have its share of incomprehensible features,
but I think this one's a bit of buglette too. Especially
considering that it works "right" in Perl 4.

Thanks for confirming that my years of slavery to that other P language
haven't wholly ruined my God-given capacity for intuiting Perl <wink>.

On the other hand, since the buglette is related to the
optimization of not saving and restoring the pattern match context
around every loop iteration, we might be slow to fix it, if we
can't figure a decent way to do it. Fact is that almost nobody
ever writes loop conditions with !~,

That was my first thought too (I didn't write the original code, just helped
a coworker track it down) -- "weird!", thought I. However, he came up with
a killer response​: "so why doesn't it work?".

and the buglette won't show up with =~ because then the pattern
doesn't match on the last iteration, and $1 wouldn't be set anyway.

As another followup noted, and as another part of the test case showed, the
same problem occurs with =~ provided that the "while" is changed to "until".
The program was chewing thru a log file where it was much easier to
recognize interesting lines than (the more-frequenct) junk lines, so

until (<> =~ /$interesting/o) {
  # chew the junk
}
# do something interesting with the interesting line

is really quite natural! It was only relative lack of Perl experience that
caused the more convoluted

while (<> !~ /$interesing/o) ...

form.

Plus nowadays there's a bit of a magical lexical scope around
entire while loops and if statements as well. (Not that your
buglette is lexical, it's dynamic.) But anyway, if you write​:

$wink = "y'rs\n";
if (my $wink = "wink-ly ") {
print $wink;
}
print "$wink";

You'll find that it prints "wink-ly y'rs", despite the fact that
the my is not within a syntactic block. I suspect that's a feature.

While tempted to accuse you of blatant misdirection here <wink>, I agree --
that's a feature. I see it as shorthand for introducing a lexical block
vrbl in the test condition -- convenient and helpful! No problem.

Your buglette is a bit less of a feature, I'd say.

Mind, I'm not promising we won't fix it. I don't make promises
like that. :-)

It proved easy to work around (just do explicit assignment to a "real vrbl"
in the test), so it's surely not a big deal. The other side is that he
spent an hour puzzling over the docs unable to find a reason for why his
code wasn't working. In retrospect, I'm kinda amazed I never bumped into it
either!

Nice to hear from you after your long sojourn in snake-strewn lands!

Nice, too, to be heard. Thanks for your insights here, Larry!

i-only-hang-out-with-pythons-cuz-the-pay-is-so-good<wink>-ly y'rs - tim

@p5pRT
Copy link
Author

p5pRT commented Jan 29, 2000

From @RandalSchwartz

"Ronald" == Ronald J Kimball <rjk@​linguist.dartmouth.edu> writes​:

Ronald> Coincidentally, I happened to stumble across this quirk earlier today while
Ronald> commenting on a script on another list. In this case, it was roughly​:

Ronald> until ($line =~ /regex/) {
Ronald> $line = <>;
Ronald> }
Ronald> if ($line =~ /regex/) {
Ronald> print $&;
Ronald> }

Ronald> This could have been simplified to​:

Ronald> until ($line =~ /regex/) {
Ronald> $line = <>;
Ronald> }
Ronald> print $&;

Ronald> were it not for this behavior. And no !~ in the loop conditional, either.
Ronald> :)

See, that's where I hate logic like this, and start creating my own
loopy things, because yours fails if you hit EOF before /regex/
matches.

  {
  last unless defined($line = <>);
  redo unless $line =~ /regex/;
  print $&;
  }

There, nice and handy. And even nearly the same number of lines. And
now that I stare at this, I'd probably go to an even more familiar
form​:

  while (<>) {
  redo unless /regex/;
  print $&;
  last;
  }

There. Very clean, no bugs visible. :)

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<merlyn@​stonehenge.com> <URL​:http​://www.stonehenge.com/merlyn/>
Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!

@p5pRT
Copy link
Author

p5pRT commented Jan 29, 2000

From [Unknown Contact. See original ticket]

"Randal L. Schwartz" wrote​:

while \(\<>\) \{
  redo unless /regex/;
  print $&;
  last;
\}

There. Very clean, no bugs visible. :)

I suppose the redo is a camouflaged next, then?

--
Rick Delaney
rick.delaney@​home.com

@p5pRT
Copy link
Author

p5pRT commented Jan 29, 2000

From @RandalSchwartz

"Rick" == Rick Delaney <rick.delaney@​home.com> writes​:

Rick> "Randal L. Schwartz" wrote​:

while (<>) {
redo unless /regex/;
print $&;
last;
}

There. Very clean, no bugs visible. :)

Rick> I suppose the redo is a camouflaged next, then?

oops. Yes, "next".

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<merlyn@​stonehenge.com> <URL​:http​://www.stonehenge.com/merlyn/>
Perl/Unix/security consulting, Technical writing, Comedy, etc. etc.
See PerlTraining.Stonehenge.com for onsite and open-enrollment Perl training!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant