Impossible to put a map in sink context

In your example, the map returns a Seq with Sunk objects in it. The entire Seq is sunk, which effectively calls Seq.iterator.sink-all, which does not sink all of its elements: it just pulls the Seq empty by calling pull-one until IterationEnd is returned.


I won't explain much as I go, leaving the bulk of it till the end.

I'm trying to see the way of throwing a map in sink context.

Adding --> Nil as the block's return value does that:

(1..3).map: -> $_ --> Nil { Sunk.new( :titanic($_) ) }

The for loop effectively sinks all the created, the map does not.

By default, blocks run with:

  • All statements but the last in sink context.

  • The last statement not in sink context. (The last statement is the block's return value so it's presumed to be inappropriate to throw it down the sink.)

Your code didn't alter this default for your map call so the block's last statement -- its only statement -- was not in sink context. (Adding --> Nil to the block's signature puts the last statement back in sink context.)

Exceptions to this default scheme involve some sort of statement keyword. for is one of these -- it puts its statement, or the last statement in its block, in sink context. (To undo that, so that the last statement is not in sink context, you can write something like $ = do for ....)

This test in roast is supposed to work as a test for that. And map is effectively in a sink context, but I don't see how it's "run as sunk". It's simply run.

I'm confused by the corresponding ticket and the test. So, sorry, I can't help on that one.


I did hours of research in preparing this answer. Some of the pieces I found and relied on for it follow, along with brief notes by me.

Many of the following links go to particular lines of IRC logs. My intent for most of those is that you read a little of the dialog that follows each line to maximize what you get from it (even if it's confusion, because I think even that might be helpful, as I explain next).

Please consider reading at least the summaries below, and clicking some of the links, and then post comments under this answer to provoke further discussion here to see if we can move towards clarity.

  • Larry begins implementing sink handling in STD (2010). Included mostly to establish the point where he began putting the sink concept for raku into code form (in the STD parser).

  • Patrick asks for clarity regarding example sub foo() { for @list { .say } }; foo(); 1 (2010). Please focus on the dialog between Patrick and Larry (TimToady) about what Larry wanted and ignore sidetracks.

  • TimToady: "sink context is very important for figuring out awesome error messages" (2012). (I think of raku's sink feature as an extreme torment implementors issue; cf the issue tracker links below.)

  • jnthn: "Note that eager context and sink context are different. Sink context should make a for loop (or map) not build a result list" (2012) This is the other piece to sink context. It's not just about awesome error messages; it's also about performance.

  • TimToady: "anyway, --> Nil seems like pretty good documentation of a procedure done only for its side-effects" (2012)

  • TimToady: "we could go as far as to have separate declarators for "procedures", but just having a sink return type already seems to say that" (he meant --> Nil) (2012)

  • jnthn asks: "TimToady: Any feeling on https://rt.perl.org/Ticket/Display.html?id=126005 ? Basically, things like loops sink their last statement, so the loop block evaluates to Nil, so the UNDO phaser fires." (2015) (More tormenting of the implementors...)

  • 9 open issues in rakudo/rakudo matching a search for "last statement"

  • Several open issues in rakudo/rakudo matching a search for "zoffix sink"; note especially Flaws in implied sinkage / &unwanted helper #157 ticket.

Tags:

Raku