Search code examples
rakuintrospectionrakudo

Is it possible to introspect into the scope of a Scalar at runtime?


If I have the following variables

my $a    = 0;
my $*b   = 1;
state $c = 2;
our $d   = 3;

I can easily determine that $*b is dynamic but $a is not with the following code

say $a.VAR.dynamic;
say $*b.VAR.dynamic;

Is there any way to similarly determine that $c is a state variable and $d is a package-scoped variable? (I know that I could do so with a will trait on each variable declaration, but I'm hopping there is a way that doesn't require annotating every declaration. Maybe something with ::(...) interpolation?)


Solution

  • As Elizabeth Mattijsen correctly noted, it is currently not possible to see whether a variable is a state variable at run time. ... at least technically at runtime.

    However, as Jonathan Worthington's comment implies, it is possible to check this at compile time. And, absent deep meta-programming shenanigans, whether a variable is a state variable is immutable after compile-time. And, of course, it's possible to make note of some info at compile time and then use it at runtime.

    Thus, it's possible to know, at runtime, whether a variable is a state one with (compile-time) code along the following lines, which provides a list-state-vars trait that lists all the state variables in a function:

    multi trait_mod:<is>(Sub \f, :$list-state-vars) {
        use nqp;
        given f.^attributes.first({.name eq '@!compstuff'}).get_value(f)[0] {
           say .list[0].list.grep({try .decl ~~ 'statevar'}).map({.name});
        }
    };
    

    This code is obviously pretty fragile/dependent on the Rakudo implementation details of QAST. Hopefully this will be much easier with RAST, but this basic approach is already workable and, in the meantime, this guide to QAST hacking is a helpful resource for this sort of meta programming.