raku

Breaking brace after the start keyword


This is the simple program, it prints a terminal size when you resize it:

#!/bin/env raku
use NCurses;
initscr;
loop {
    given getch() {
        when 27 { last } # exit when pressing esc
        when KEY_RESIZE {
            mvprintw 0, 0, "{LINES}x{COLS}";
            nc_refresh
        }
    }
}

endwin;

Let's add await start { ... } around the loop:

await start { loop {
    given getch() {
        ### code
    }
} }

Now this program doesn't work properly: it doesn't print anything when I resize a terminal, but prints the size when I press any key. Note that it still handles esc press correctly.

Finally, let's remove the curly braces and the program will work as it should again:

await start loop {
    given getch() {
        ### code
    }
}

What is this dirty magic with start and braces?


Solution

  • A loop statement (at block level) iterates immediately. By contrast, a loop expression produces a lazy generator.

    When the start block has curly braces, then it's clearly a loop statement, because it's in a block. Thus the loop executes on another thread.

    Without them, the compiler is considering it a loop expression (it's an interesting question whether it should). The start schedules the work on another thread, but the work it schedules is merely producing a lazy generator, not actually doing any iteration. Thus it completes immediately, and the await produces the lazy generator. Since the await is in sink (void) context, the generator is iterated. Note that since this is after the await, then the loop is executing on the main thread.

    So only the curly form actually executes off the main thread, and it would appear that doesn't sit well with the NCurses library. I'm afraid I've no insights into why that would be.