Should Raku run MAIN if the file is required?
Asked Answered
P

1

6

Here's a short Raku program that declare a MAIN subroutine. I should only see output if I execute the program directly:

$ cat main.rakumod
sub MAIN { say "Called as a program!" }

And I see output when I execute the program directly:

$ raku main.rakumod
Called as a program!

If I load it as a module, I see no output:

$ raku -I. -Mmain -e "say 'Hey'"
Hey

Same if I use it from inside the program, I see no output:

$ raku -I. -e 'use main'

But, if I use require, I get output:

$ raku -I. -e 'require <main.rakumod>'
Called as a program!

Synopsis 06 literally says the compilation unit was directly invoked rather than by being required. Is there something else going on because require works at runtime (although S06 doesn't exclude that)?

I get the same behaviour with Rakudo Star 2016.07 and 2016.10.

Parrott answered 24/11, 2016 at 5:48 Comment(3)
does it make a difference if you omit the file extension?Hierolatry
@Christoph: without the file extension for require, it doesn't find the file.Parrott
makes sense - the proper syntax for what I had in mind is require ::('main')Hierolatry
H
4

First, let's take a look at how require is supposed to behave:

According to the (non-authorative) design documents,

Alternately, a filename may be mentioned directly, which installs a package that is effectively anonymous to the current lexical scope, and may only be accessed by whatever global names the module installs:

and

Only explicitly mentioned names may be so imported. In order to protect the run-time sanctity of the lexical pad, it may not be modified by require.

In combination with S06's

This call is performed if and only if:

a) the compilation unit was directly invoked rather than by being required by another compilation unit [...]

it is my understanding that a sub MAIN not explicitly imported into the mainline lexical scope should not be run.

Sadly, the user documentation is quiet on the case of runtime importation via file name, and a quick glance at the (authorative) test suite (in particular S11-modules/require.t) did not yield an answer either, though I just might have missed it.

Now, let's take a look at how Rakudo behaves:

As expected, runtime importation via static or dynamic module name

require main;

or

require ::('main');

will not run MAIN unless it is both declared is export and explicitly imported, ie

require main <&MAIN>;

and

require ::('main') <&MAIN>;

respectively.

Importation via file name however

require 'main.rakumod';

will immediately run MAIN.

In fact, if you do a proper import via

require 'main.rakumod' <&MAIN>;

the sub will be executed twice: Once when loading the compilation unit, and a second time when the runtime does its job looking and running any MAIN sub in the mainline scope.

Rakudo apparently treats a require with file name argument more or less like EVALFILE and executes its mainline, including any sub MAIN it encounters.

That's not what I would have expected and possibly just a bug.

Hierolatry answered 25/11, 2016 at 12:23 Comment(3)
This is some good info, and I also wouldn't expect MAIN to run unless it's in the mainline code. That is, actually in the file originally run. If it comes from any other file, it shouldn't run. That includes EVALFILE.Parrott
@briandfoy: agreed, tentatively: if EVALFILE no longer executes MAIN, there probably should be an alternative that does (a named parameter to EVALFILE? a new sub RUNFILE? a sh-style SOURCEFILE? ...)Hierolatry
Yeah, tricky. But, if it's documented that it goes one way or the other I can work with that even if it does something different. But, maybe you could read a file into a string and eval that string.Parrott

© 2022 - 2024 — McMap. All rights reserved.