How can I terminate a loop started in a BEGIN block?

Viewed 138

I would like to show a progress bar while the application is loading/initializing.

This code doesn't work, but should give you an idea of what I'm trying to accomplish.

my Bool $done-compiling = False;
BEGIN {
    start repeat {
        print '*';
        sleep 0.33;
    } until $done-compiling;
};

INIT {
    $done-compiling = True;
};

Is there an event triggered that I could respond to in the BEGIN block?

3 Answers

Liz has provided a solution in terms of the code you'd written, fixing the bug that was in your original.

Here's a simpler version:

BEGIN start repeat { print '*'; sleep 0.33 } until INIT True

(You might be thinking INIT True is some special feature but it just falls out naturally from how phasers that return a value work.)

I think the code is ok. And if you simulate loading, you'll see a progress bar of *'s:

my Bool $done-compiling;
BEGIN {
    start repeat {
        print '*';
        sleep 0.33;
    } until $done-compiling;
}

BEGIN sleep 3; # simulate compilation / loading

INIT $done-compiling = True;

Setting the flag in the INIT block should be enough! I guess you could consider execution of the INIT block to be the event you're looking for?

You've already gotten two answers that work. But both of them rely on using variables across different threads, which always makes me a bit nervous. Given that we need multiple threads here, I'd probably turn to one of Raku's helpful concurrency primitives. Here's a very minor change to the accepted answer that uses a Promise:

my Promise $done-compiling;
BEGIN {
    $done-compiling .= new;
    start repeat {
        print '*';
        sleep 0.33;
    } until $done-compiling ~~ Kept;
}

BEGIN sleep 3; # simulate compilation / loading

INIT $done-compiling.keep;
Related