Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are perl6 subs really lexically scoped or have extra?

Tags:

scope

raku

If I have a block like the following:

{
   say $myVar;
   my $myVar=1;
}

I get the expected error:

Variable '$myVar' is not declared 

However in a similar fashion with a sub

{
    test();
    my sub test() {
        say "Hello";
    }
}

This runs without error and prints:

Hello

Both $myVar and test are not visible outside of enclosing blocks, so in that sense they are both lexically scoped.

The sub must have its declaration 'hoisted' to the top of the block as test is defined and usable before its position in the code. I can't find a reference to back this up however.

What prompted this question is looking at lexical scoped my subs in perl, which gives an 'undefined subroutine' error in the perl version of the second case above. In my understanding of lexical scope, this is what I would expect.

I use this without thought... write some test code, later wrap it up into a sub declared at a bottom of my file and call the sub from earlier in the file. Everything works!

It does leads to the question: Are perl6 subs really lexically scoped in this sense?

like image 517
drclaw Avatar asked Jun 26 '19 17:06

drclaw


Video Answer


2 Answers

From the Subroutine Apocalypse:

Perl 6 also allows you to defer declaring your subroutine till later in the file, but only if the delayed declaration declares the sub to be parsed consistent with how a list operator would be parsed. Basically, any unrecognized "bareword" is assumed to be a provisional list operator that must be declared by the end of the current compilation unit.

like image 42
LuVa Avatar answered Nov 08 '22 04:11

LuVa


When Perl6 comes across a function call it makes a note about it, but it does not check if the function is there.

So the following will compile, but will not actually work. (The function is not available where it is called.)

foo 1;
my &foo = &say;

In the following the compiler does the same thing, but then the optimizer realizes that it can't even find a reference to the function anywhere. (So the optimizer causes it to fail during compilation.)

bar 1;

The reason for this difference to other variables is that many times you may have one function that relies on another, or you want to place the functions after the rest of the code.
Also the code of a function is usually known at compile-time, whereas the value of a variable isn't known until after it is assigned. (The assignment happens at run-time.)

Basically the way people tend to use variables and functions is different, so they work slightly differently.

There isn't a need to require them to be declared before they are used, so that restriction was removed.


In Perl5 functions modify the parser based on their prototype, so the compiler needs to see a declaration before they are used for it to know how they should be parsed.

use v5.10;

sub foo ();
sub bar;

say foo + 1; # foo() + 1 # foo is compiled as a term/constant
say bar + 1; # bar( +1 )

sub foo () { 2 }
sub bar { $_[0] + 2 }

In Perl6 all functions are compiled as if they take a list, so there is no need to require them to be predeclared.

use v6;

# these two lines don't really change anything.
sub foo () {...}
sub bar ($) {...}


say foo + 1; # foo( +1 ) # optimization failure (too many arguments)
say bar + 1; # bar( +1 )

sub foo () { 2 }
sub bar ( $a ) { $a + 2 }
like image 194
Brad Gilbert Avatar answered Nov 08 '22 03:11

Brad Gilbert