Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic variables and promises

It seems that dynamic variables don't always survive subroutine calls in threads:

sub foo($x, &y = &infix:<+>) {
  my &*z = &y;
  bar($x);
}

sub bar ($x) {
    say &*z($x,$x);

    my $promise = start { bar($x-1) if $x > 0 }
    await $promise;

    # bar($x-1) if $x > 0    # <-- provides the expected result: 6, 4, 2, 0
}
foo(3); # 6, 4, Dynamic variable &*z not found

Using a more globally scoped variable also works, so it's not that all variables are lost — it seems specific to dynamics:

our &b;

sub foo($a, &c = &infix:<+>) {
  &b = &c;
  bar($a);
}

sub bar ($a) {
    say &b($a,$a);
    my $promise = start { bar($a-1) if $a > 0 }
    await $promise;
}

foo(3); # 6, 4, 2, 0

Once the variable is set in foo(), it is read without problem in bar(). But when bar() is called from inside the promise, the value for &*z disappears not on the first layer of recursion but the second.

I'm sensing a bug but maybe I'm doing something weird with the between the recursion/dynamic variables/threading that's messing things up.

like image 651
user0721090601 Avatar asked Aug 20 '19 21:08

user0721090601


1 Answers

Under current semantics, start will capture the context it was invoked in. If dynamic variable lookup fails on the stack of the thread that the start executes on (one of those from the thread pool), then it will fall back to looking at the dynamic scope captured when the start block was scheduled.

When a start block is created during the execution of another start block, the same thing happens. However, there is no relationship between the two, meaning that the context captured by the "outer" start block will not be searched also. While one could argue for that to happen, it seems potentially problematic to do so. Consider this example:

sub tick($n = 1 --> Nil) {
    start {
        await Promise.in(1);
        say $n;
        tick($n + 1);
    }
}
tick();
sleep;

This is a (not entirely idiomatic) way to produce a tick every second. Were the inner start to retain a reference back to the state of the outer one, for the purpose of dynamic variable lookup, then this program would build up a chain of ever increasing length in memory, which seems like an undesirable behavior.

like image 70
Jonathan Worthington Avatar answered Nov 15 '22 07:11

Jonathan Worthington