00:21 finanalyst joined 00:26 finanalyst left 00:52 finanalyst joined 00:56 finanalyst left 01:23 finanalyst joined 01:27 finanalyst left 02:24 finanalyst joined
[Coke] I thought dd would give me more detail, and say would give me a gist. 02:25
just my initial feeling. 02:26
02:29 finanalyst left 02:55 finanalyst joined 02:58 guifa joined 03:00 finanalyst left, guifa left 03:26 finanalyst joined 03:30 finanalyst left 03:56 finanalyst joined 04:01 finanalyst left 04:27 finanalyst joined 04:32 finanalyst left 04:58 finanalyst joined 05:03 finanalyst left 05:29 finanalyst joined 05:33 finanalyst left 06:00 finanalyst joined 06:04 finanalyst left 06:30 finanalyst joined 06:35 finanalyst left 07:01 finanalyst joined 07:05 finanalyst left 07:32 finanalyst joined 07:36 finanalyst left 08:03 finanalyst joined 08:07 finanalyst left 08:33 finanalyst joined 08:38 finanalyst left
ShimmerFairy Found an absolutely wild bug today in rakudo (or at least what looks like one). Basically, a .map inside a for loop inside a subroutine call can't modify outside-context variables (originally, a dynvar) without doing something inside the sub to force it. 08:49
m: my $x = 42; sub modify() { for 1 { (4,5,6).map({$x += $_}) } }; say $x; modify(); say $x
camelia 42
42
ShimmerFairy m: my $x = 42; sub modify() { for 1 { (4,5,6).map({$x += $_}).eager } }; say $x; modify(); say $x # using .eager makes it work
camelia 42
57
ShimmerFairy m: my $x = 42; sub modify() { for 1 { (4,5,6).map({$x += $_}) }; say "(Debug: $x)" }; say $x; modify(); say $x # using debug prints to diagnose the issue also makes it work 08:50
camelia 42
(Debug: 57)
57
ShimmerFairy I've tried a number of variations that all avoid the issue, whether it's using a second loop instead of a map, or using a 'repeat while False' loop instead of a for loop. There seems to be a very narrow window where the bug appears. 08:51
Of course I'll file a bug for this, just had to mention it here first.
09:57 finanalyst joined 10:43 [Tux] left 10:48 [Tux] joined 11:15 finanalyst left
SmokeMachine m: my @a := ^10 .map: { .say }; say “after”; .say for @a 11:24
camelia 0
Type check failed in binding; expected Positional but got Seq ((Bool::True, Bool::T...)
in block <unit> at <tmp> line 1

1
2
3
4
5
6
7
8
9
SmokeMachine m: my $a = ^10 .map: { .say }; say “after”; .say for @$a 11:25
camelia after
0
True
1
True
2
True
3
True
4
True
5
True
6
True
7
True
8
True
9
True
lizmat ShimmerFairy: the problem is really that the last statement in a scope is not sunk
SmokeMachine ShimmerFairy: I don’t think that’s a big… but Seqs are lazy… so it will only run when you try to get the data 11:26
lizmat m: class A { method sink() { say "sunk" } }; sub a() { A }; a' 11:27
camelia ===SORRY!=== Error while compiling <tmp>
Two terms in a row
at <tmp>:1
------> ink() { say "sunk" } }; sub a() { A }; a<HERE>'
expecting any of:
infix
infix stopper
statement end
statement modifier…
lizmat m: class A { method sink() { say "sunk" } }; sub a() { A }; a
camelia ( no output )
ShimmerFairy I'd still call it a bug, because it does work in some contexts (like if the map is in a subroutine all on its own)
m: my $x = 42; sub modify() { (4,5,6).map({$x += $_}) }; say $x; modify(); say $x
camelia 42
57
SmokeMachine m: my $x = 42; sub modify() { (4,5,6).map({$x += $_}) }; say $x; my $a = modify(); say $x 11:28
camelia 42
42
lizmat in any case, I vaguely recall this being reported ~ 8 years ago (I think even by me) and that jnthn had some explanation for it 11:29
SmokeMachine Your worked because the Seq was sunk, so it ran…
ShimmerFairy OK, so why does the last statement of the for loop not sink? for loops don't appear to return the value of their last statement, so it can't be for that (and even then, I'd expect it to ultimately sink when the calling function does nothing with the value) 11:31
lizmat a .map produces a Seq: that doesn't do anything by itself 11:32
SmokeMachine Because it returns 11:33
m: Seq.^find_method("sink").wrap: -> | { say "sunk"; callsame }; my $x = 42; sub a { ^10 .map: { $x += $_ } }; a; say $x
camelia sunk
87
lizmat a for loop gets something Iterable and a block, and calls the block for each value the iterator of the Iterable produces
SmokeMachine Seq.^find_method("sink").wrap: -> | { say "sunk"; callsame }; my $x = 42; sub a { ^10 .map: { $x += $_ } }; my $a = a; say $x 11:34
evalable6 42
SmokeMachine See? No “sunk”
ShimmerFairy m: sub foo() { for 1,2,3 { $_ } }; say foo() 11:35
camelia Nil
ShimmerFairy If the for loop isn't sinking the last value, and it also isn't returning it up to the outer block, then what exactly is it doing?
lizmat produces a Seq that doesn't get iterated
m: my $a = (1,2,3).map(*.say); $a = 42 11:36
camelia ( no output )
SmokeMachine Yeah… maybe a for loop (with no `do`) should sink?
ShimmerFairy You could argue that it was wrong of me to use .map when I wasn't trying to produce a list of transformed values (and instead just using it as a compact way of writing a for loop), but I still think there's something inconsistent and surprising here. 11:39
I did make an issue for it, btw, where I was able to simplify the example a bit further: github.com/rakudo/rakudo/issues/6912 11:40
lizmat one should really be aware that .map just produces a Seq
and that it doesn't run by itself 11:41
SmokeMachine I think the problem here is not map, but the last statement of a for block not sinking… 11:42
lizmat well, the statement of a block cannot be sunk because it can be returned
SmokeMachine m: Seq.^find_method("sink").wrap: -> | { say "sunk"; callsame }; my $x = 42; sub a { for 1 { ^10 .map: { $x += $_ } } }; a; say $x # this does not sink
camelia 42
SmokeMachine But inside a for (with no `do`) it’s not returned… 11:43
m: Seq.^find_method("sink").wrap: -> | { say "sunk"; callsame }; my $x = 42; sub a { for 1 { ^10 .map: { $x += $_ }; 42 } }; a; say $x # this sinks
camelia sunk
87
lizmat and "for 1,2,3 { foo }" is basically (1,2,3).map({ foo }).sink under the hood
m: my $a = (1,2,3).map(*.say); $a.sink 11:44
camelia 1
2
3
lizmat m: my $a = (1,2,3).map(*.say); say "Seq made"; $a.sink
camelia Seq made
1
2
3
SmokeMachine But it seems for is not calling that .sink at the end, is it?
lizmat the for is basically calling the .sink on the Seq that the .map creates 11:45
ShimmerFairy but then why is it *not* doing what Seq sinking does when that for loop is the last statement of a subroutine? 11:48
SmokeMachine If it were calling sink, a and b here should behave the same, no? 11:50
m: Seq.^find_method("sink").wrap: -> | { say "sunk"; callsame }; my $x = 42; sub a { for 1 { ^10 .map: { $x += $_ } } }; sub b { (1).map({ ^10 .map: { $x += $_ } }).sink }; say "calling a: "; $ = a; say "calling b: "; $ = b
camelia calling a:
calling b:
sunk
ShimmerFairy I just don't see the justification for the current behavior. It doesn't sink, and the for loop doesn't "return" anything either, so what is this secret third thing where it disappears entirely? 11:51
m: (1,2,3).map({say "outer"; (4,5,6).map({say "inner"})}) # as in my bug report, you also see this with nested maps 11:52
camelia outer
outer
outer
lizmat github.com/rakudo/rakudo/issues/1571 11:53
SmokeMachine m: (1,2,3).map({say "outer"; (4,5,6).map({say "inner"}).sink }) 11:54
camelia outer
inner
inner
inner
outer
inner
inner
inner
outer
inner
inner
inner