00:27 librasteve_ left 08:04 sourceable6 left, sourceable6 joined, Geth left, notable6 left, sourceable6 left, sourceable6 joined, linkable6 left, greppable6 left 08:05 greppable6 joined, linkable6 joined, notable6 joined
lizmat m: sub b { Promise.kept.then({ return 42 }).result }; say b # guess this is a DIHWIDT ? 10:36
camelia MoarVM panic: Did not find expected unwind target frame.
timo shouldn't cause a panic though 10:45
lizmat I seem to recall this is the type of case that fixing would slow down MoarVM generally quite a bit, no ? 10:49
timo not sure, it should be possible at the location of the error happening we could do a bit of extra work to figure out if it was a critical problem (internal bug or whatever) or if we can just throw an exception telling the user that they did an oopsie 10:54
Voldenet it would be best if blocks could have conditional exception handlers 10:57
m: sub b { Promise.kept.then(sub { return 42 }).result }; say b # so the above would turn into something like this
camelia Tried to get the result of a broken Promise
in sub b at <tmp> line 1
in block <unit> at <tmp> line 1

Original exception:
Too many positionals passed; expected 0 arguments but got 1
in sub at <tmp> line 1
timo i think the code that runs a "then" may need to have a handler for "return" control exceptions that reacts in this kind of situation 11:00
Voldenet m: sub b { 42.map({ $^a.return }) }; say b # I bet this may be a bit head-scratching 11:01
camelia Attempt to return outside of immediately-enclosing Routine (i.e. `return` execution is outside the dynamic scope of the Routine where `return` was used)
in block <unit> at <tmp> line 1
Voldenet otoh
hm, nah, I can't think of an example where this exception is useful 11:02
timo the exception from the last execution you mean? 11:03
Voldenet yes
timo i'm not sure how you mean "useful" 11:04
Voldenet I mean, I wonder if the situation where you throw return control exception in a block is useful
I know there is difference, but I can't think of any useful scenario 11:05
timo recall that if also works with blocks
and if you're factoring out some code from a sub and the code you're moving has a return in it, if you use blocks rather than subs for the factored out portion you can return from there instead of having to write `return $_ with mysub()` every time you call it 11:06
Voldenet ah, right, of course
timo if and for and other constructs
that's i think the primary motivation for blocks being transparent to return control exceptions 11:07
also, early return from a sub that uses map is something that can be useful
Voldenet m: sub { 42.map({ return $^x }) }().say; # this doesn't work though 11:08
camelia Attempt to return outside of immediately-enclosing Routine (i.e. `return` execution is outside the dynamic scope of the Routine where `return` was used)
in block <unit> at <tmp> line 1
Voldenet iirc it works with CX::Last 11:10
timo yeah, map is lazy 11:11
last will make the iterator stop generating new values, which is completely fine to do after the enclosing sub has returned
Voldenet m: v6.e.PREVIEW; sub { 42.map({ last $^x }) }().say; # …I don't remember, maybe this
camelia Cannot resolve caller last(Int:D); none of these signatures matches:
( --> Nil)
(Label:D $x --> Nil)
in block <unit> at <tmp> line 1
timo m: sub { 42.map({ return $^x }); say "never reached"; }().say
camelia 42
Voldenet (nah, it was for grep) 11:12
timo m: sub { <a b c d e>.map({ last when "c"; $_ }) }().say
camelia (a b)
timo no last-with-value i guess 11:13
Voldenet i mean the form with "last(Bool)" that tells grep whether to include the value or not
I confused it with map for some reason
I get the behavior with early return and it is somewhat understandable 11:14
timo AFKBBL 11:15
Voldenet m: sub { for 42 { return $^x } }().say; # this is something I fully expect in the context 11:16
camelia 42
Voldenet m: sub { 42.map({ return $^x }); 1 }().say; # having to type in that another statement is a bit odd, still 11:17
camelia 42
Voldenet m: sub { 42.map({ return $^x }); }().say; # otherwise this happen
camelia Attempt to return outside of immediately-enclosing Routine (i.e. `return` execution is outside the dynamic scope of the Routine where `return` was used)
in block <unit> at <tmp> line 1
Voldenet I'm not very strong in this opinion, but maybe "return inside block" should instead let you do this 11:18
m: sub { 42.map({ when 42 { .return }; return 1 }); 1; }().say; # the whole sub returns 42, there's no way to escape the block without additional sub… 11:21
camelia 42
Voldenet m: sub { 42.map(sub { when 42 { .return }; return 1 }); 1; }().say; # so you need that extra handler 11:22
camelia Too many positionals passed; expected 0 arguments but got 1
in sub at <tmp> line 1
in sub at <tmp> line 1
in block <unit> at <tmp> line 1
Voldenet m: sub { 42.map(sub($) { when 42 { .return }; return 1 }); 1; }().say; # so you need that extra handler
camelia ===SORRY!=== Error while compiling <tmp>
Unable to parse expression in argument list; couldn't find final ')' (corresponding starter was at line 1)
at <tmp>:1
------> sub { 42.map(sub($)<HERE> { when 42 { .return }; return 1 }); 1;
expect…
Voldenet m: sub { 42.map(sub ($) { when 42 { .return }; return 1 }); 1; }().say; # so you need that extra handler
camelia 1
Voldenet in such cases people use ternary op or pattern matching, but often guard statements are more readable, because they don't introduce additional blocks inside a block 11:24
e.g. `return Empty if …;` 11:25
lizmat m: dd do if 0 { } 11:27
camelia Empty
lizmat a failed conditional already returns Empty
m: dd (^10).map({ $_ if $_ %% 2 }) # which is why this works 11:28
camelia (0, 2, 4, 6, 8).Seq
Voldenet yes but I meant code like this `"{ y: 42 }".map({ return Empty unless my $x = .&json_parse; return Empty unless my $n = $x<y>; $n + 5 }` 11:31
I have no strong opinion, because one can simply add that "sub ($_)" inside a map(…) and it solves the problem 11:32
it's not the best example though… `sub { return 42.map({ .&json_parse andthen .<y> andthen * + 5 }) }().say;` 11:35
but still, guard statements are useful for handling exceptional cases in .map 11:36
12:12 Geth joined
timo sorry i'm not sure what you mean by "extra handler" there 14:25
but the oddness happening with "map" is that when you put it as the last statement, it becomes the return value as a value, and if you don't sink or iterate or otherwise consume it, the code in the block you're mapping onto the sequence doesn't run yet 14:27
it's also a footgun when you return a sequence from a block you are using Lock.protect in; the code lexically inside the lock's protection may actually run later 14:29
a future hypothesized linter, or actually the jetbrains plugin, could point something like that out 14:32
am i correctly picking up what you're putting down? 14:34
Voldenet I just mentioned that as weird as an aside, but I understand the explanation 16:07
but by extra handler I mean that if you want to use map({ return … }) you need to use map(sub ($_) { return … })
timo m: .say for <a b c d e f g>.map({ if $_ eq "c" { leave "leave test" }; $_ ~ "+"; }) 16:09
camelia a+
leave not yet implemented. Sorry.
in block <unit> at <tmp> line 1

b+
Voldenet :>
Yes, it would make sense if leave worked, I guess it's specified well 16:10
not having return is a bit visible in Promise.then and in that case return doesn't even make much sense 16:18
unless it's awaited in the same sub where the block originates from 16:20
e.g. `sub x { await fetch("thing").then(sub ($_) { return 0 if .status ~~ Broken; .result })` 16:22
without `sub ($_)` x could return 0 directly without resolving the promise, but that'd be weird 16:26