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

S/// within map doesn't work #5886

Closed
p6rt opened this issue Dec 15, 2016 · 7 comments
Closed

S/// within map doesn't work #5886

p6rt opened this issue Dec 15, 2016 · 7 comments

Comments

@p6rt
Copy link

p6rt commented Dec 15, 2016

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

Searchable as RT130355$

@p6rt
Copy link
Author

p6rt commented Dec 15, 2016

From @bduggan

This code​:

  say <a1 a2 a3>.map({S/a/x/}).perl

returns this​:

  ("x3", "x3", "x3").Seq

instead of x1, x2, x3.

Version​: 2016.11

IRC snippet below.

[12​:27] == bdmatatu [6c347aa0@​gateway/web/freenode/ip.108.52.122.160] has joined #perl6
[12​:30] <bdmatatu> p6​: say <a1 a2 a3>.map({S/a/x/}).perl
[12​:30] <+camelia> rakudo-moar 9a3c35​: OUTPUT«("x3", "x3", "x3").Seq␤»
[12​:30] == dakkar [~dakkar@​2001​:8b0​:6448​:5fae​:b18a​:bf2​:877d​:4f6d] has quit [Ping timeout​: 245 seconds]
[12​:30] <bdmatatu> I was expecting x1 x2 x3
[12​:35] <AlexDaniel> bdmatatu​: interesting… looks like there's something wrong with .perl?
[12​:35] <AlexDaniel> bisect​: say <a1 a2 a3>.map({S/a/x/}).perl
[12​:36] <+bisectable6> AlexDaniel, On both starting points (old=2015.12 new=9a3c350) the exit code is 0 and the output is identical as well
[12​:36] <+bisectable6> AlexDaniel, Output on both points​: ("x3", "x3", "x3").Seq
[12​:36] <AlexDaniel> commit​: all say <a1 a2 a3>.map({S/a/x/}).perl
[12​:36] <+committable6> AlexDaniel, https://gist.github.com/e5004d10ec77d2addd00e40d6f1a6771
[12​:37] == donaldh [chatzilla@​nat/cisco/x-adftzffgeuuokccx] has quit [Remote host closed the connection]
[12​:39] <bdmatatu> p6​: say <a1 a2 a3>.map({ S/a/x/ })[0]
[12​:39] <+camelia> rakudo-moar 9a3c35​: OUTPUT«x1␤»
[12​:39] <bdmatatu> p6​: say <a1 a2 a3>.map({ S/a/x/ }).eager[0]
[12​:39] <+camelia> rakudo-moar 9a3c35​: OUTPUT«x3␤»
[12​:40] <AlexDaniel> m​: say <a1 a2 a3>.map({S/huh//})
[12​:40] <+camelia> rakudo-moar 9a3c35​: OUTPUT«(a1 a2 a3)␤»
[12​:40] <AlexDaniel> m​: say eager <a1 a2 a3>.map({S/huh//})
[12​:40] <+camelia> rakudo-moar 9a3c35​: OUTPUT«(a3 a3 a3)␤»
[12​:41] <AlexDaniel> huggable​: bug report
[12​:41] <huggable> AlexDaniel, nothing found
[12​:41] <AlexDaniel> huggable​: bug
[12​:41] <huggable> AlexDaniel, nothing found
[12​:41] <AlexDaniel> huggable​: report bug
[12​:41] <huggable> AlexDaniel, nothing found
[12​:41] <AlexDaniel> meh
[12​:41] <AlexDaniel> bdmatatu​: anyway, this looks like a bug, can you submit a ticket?
[12​:41] <bdmatatu> Okay, sure, thanks

@p6rt
Copy link
Author

p6rt commented Dec 15, 2016

From @zoffixznet

I nursed this one to know where the problem is, but unsure of the fix. Maybe someone can figure out how to push it through the finish line...

First, the problem shown in the OP is weird only because there's a level of indirection with the iterator and the problem there shows up only after we attempt to fetch already reified items.

Here's a simpler reproduction with both S/// and s///​:

  <ZoffixW> m​: say do for <a1 a2 a3 a4> { S/a/z/; }
  <camelia> rakudo-moar 9a3c35​: OUTPUT«(z4 z4 z4 z4)␤»
  <ZoffixW> m​: say do for <a1 a2 a3 a4> -> $_ is copy { s/a./z/; }
  <camelia> rakudo-moar 9a3c35​: OUTPUT«(「a4」 「a4」 「a4」 「a4」)␤»

The problem is the `S///` and `s///` ops use the $/ and return it. This value becomes an item in the loop's result list, but the next loop iteration updates the $/, so all the previous items in the list get updated to it as well, which is why we see all items in the output set to the last item.

I looked through some past commits mentioning $/ for ideas, and tried the following, but that didn't fix anything... I'm out of ideas now.

  cpan@​perlbuild2~/CPANPRC/rakudo (nom)$ gd
  diff --git a/src/Perl6/Actions.nqp b/src/Perl6/Actions.nqp
  index 0a4acb3..5a3f3b1 100644
  --- a/src/Perl6/Actions.nqp
  +++ b/src/Perl6/Actions.nqp
  @​@​ -7781,6 +7781,13 @​@​ class Perl6​::Actions is HLL​::Actions does STDActions {
 
  $past := QAST​::Op.new( :op('locallifetime'), :node($/),
  QAST​::Stmt.new(
  + QAST​::Op.new( :op('bind'),
  + QAST​::Var.new( :name('$/'), :scope('lexical') ),
  + QAST​::Op.new(
  + :op('getlexdyn'),
  + QAST​::SVal.new( :value('$/') ),
  + )
  + ),
 
  # my $result;
  QAST​::Var.new( :name($result), :scope('local'), :decl('var') ),
  cpan@​perlbuild2~/CPANPRC/rakudo (nom)$

Cheers,
ZZ

On Thu, 15 Dec 2016 09​:47​:06 -0800, bduggan@​matatu.org wrote​:

This code​:

say <a1 a2 a3>.map({S/a/x/}).perl

returns this​:

("x3", "x3", "x3").Seq

instead of x1, x2, x3.

Version​: 2016.11

IRC snippet below.

[12​:27] == bdmatatu [6c347aa0@​gateway/web/freenode/ip.108.52.122.160]
has joined #perl6
[12​:30] <bdmatatu> p6​: say <a1 a2 a3>.map({S/a/x/}).perl
[12​:30] <+camelia> rakudo-moar 9a3c35​: OUTPUT«("x3", "x3", "x3").Seq␤»
[12​:30] == dakkar [~dakkar@​2001​:8b0​:6448​:5fae​:b18a​:bf2​:877d​:4f6d] has
quit [Ping timeout​: 245 seconds]
[12​:30] <bdmatatu> I was expecting x1 x2 x3
[12​:35] <AlexDaniel> bdmatatu​: interesting… looks like there's
something wrong with .perl?
[12​:35] <AlexDaniel> bisect​: say <a1 a2 a3>.map({S/a/x/}).perl
[12​:36] <+bisectable6> AlexDaniel, On both starting points
(old=2015.12 new=9a3c350) the exit code is 0 and the output is
identical as well
[12​:36] <+bisectable6> AlexDaniel, Output on both points​: ("x3", "x3",
"x3").Seq
[12​:36] <AlexDaniel> commit​: all say <a1 a2 a3>.map({S/a/x/}).perl
[12​:36] <+committable6> AlexDaniel,
https://gist.github.com/e5004d10ec77d2addd00e40d6f1a6771
[12​:37] == donaldh [chatzilla@​nat/cisco/x-adftzffgeuuokccx] has quit
[Remote host closed the connection]
[12​:39] <bdmatatu> p6​: say <a1 a2 a3>.map({ S/a/x/ })[0]
[12​:39] <+camelia> rakudo-moar 9a3c35​: OUTPUT«x1␤»
[12​:39] <bdmatatu> p6​: say <a1 a2 a3>.map({ S/a/x/ }).eager[0]
[12​:39] <+camelia> rakudo-moar 9a3c35​: OUTPUT«x3␤»
[12​:40] <AlexDaniel> m​: say <a1 a2 a3>.map({S/huh//})
[12​:40] <+camelia> rakudo-moar 9a3c35​: OUTPUT«(a1 a2 a3)␤»
[12​:40] <AlexDaniel> m​: say eager <a1 a2 a3>.map({S/huh//})
[12​:40] <+camelia> rakudo-moar 9a3c35​: OUTPUT«(a3 a3 a3)␤»
[12​:41] <AlexDaniel> huggable​: bug report
[12​:41] <huggable> AlexDaniel, nothing found
[12​:41] <AlexDaniel> huggable​: bug
[12​:41] <huggable> AlexDaniel, nothing found
[12​:41] <AlexDaniel> huggable​: report bug
[12​:41] <huggable> AlexDaniel, nothing found
[12​:41] <AlexDaniel> meh
[12​:41] <AlexDaniel> bdmatatu​: anyway, this looks like a bug, can you
submit a ticket?
[12​:41] <bdmatatu> Okay, sure, thanks

@p6rt
Copy link
Author

p6rt commented Dec 15, 2016

The RT System itself - Status changed from 'new' to 'open'

@p6rt
Copy link
Author

p6rt commented Feb 1, 2017

From @zoffixznet

Thank you for the report. This is now fixed.

Fix​: rakudo/rakudo@97359ae42e
Test​: Raku/roast@1ed4d128d2

It's worth noting the fix is somewhat tangental to the original issue and the issue isn't actually a bug.

What happens in the original issue is you keep returning the same container for each item mapped over (in the case of S///, it was the $/ variable). And depending on how you fetch the results, you get the *latest* value of that container. The most curious example of this effect is​:

  [12​:40] <AlexDaniel> m​: say <a1 a2 a3>.map({S/huh//})
  [12​:40] <+camelia> rakudo-moar 9a3c35​: OUTPUT«(a1 a2 a3)␤»
  [12​:40] <AlexDaniel> m​: say eager <a1 a2 a3>.map({S/huh//})
  [12​:40] <+camelia> rakudo-moar 9a3c35​: OUTPUT«(a3 a3 a3)␤»

The first version is lazy, and the value inside $/ container is "used" somewhere in say before it gets updated to the next value. In the second version, the `eager` statement modifier gets rid of that lazines, so the `say` gets three items, all of them the $/ container, and so it naturally contains whatever the last value
that was stored in it (in this case "a3"), which is why we get three items that are the same.

The rest of the weirdness in this ticket is all due to the same reason, except it may appear to not be present due to laziness, or not appear on first iteration but then appear on second one, due to first version evaluated for each lazily generated value, but then those get stored in the list's $!reified attribute and keep getting updated to new values as the list is reified further. The result is only the second iteration notices those updates.

Lastly, why is this ticket fixed now? We determined that S/// is actually not supposed to return $/. So for an unrelated reason it no longer returns the same container on multiple iterations, fixing this bug by a happy accident \o/

Cheers,
ZZ

@p6rt p6rt closed this as completed Feb 1, 2017
@p6rt
Copy link
Author

p6rt commented Feb 1, 2017

@zoffixznet - Status changed from 'open' to 'resolved'

@p6rt
Copy link
Author

p6rt commented Feb 1, 2017

From @bduggan

Great. I tested the original example with the change and verified
that it works.

  ./perl6 -e 'say <a1 a2 a3>.map({S/a/x/}).perl'
  ("x1", "x2", "x3").Seq

thanks!
Brian

1 similar comment
@p6rt
Copy link
Author

p6rt commented Feb 3, 2017

From @bduggan

Great. I tested the original example with the change and verified
that it works.

  ./perl6 -e 'say <a1 a2 a3>.map({S/a/x/}).perl'
  ("x1", "x2", "x3").Seq

thanks!
Brian

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

No branches or pull requests

1 participant