Alter how arguments are processed before they're passed to sub MAIN - program-entry-point

Given the documentation and the comments on an earlier question, by request I've made a minimal reproducible example that demonstrates a difference between these two statements:
my %*SUB-MAIN-OPTS = :named-anywhere;
PROCESS::<%SUB-MAIN-OPTS><named-anywhere> = True;
Given a script file with only this:
#!/usr/bin/env raku
use MyApp::Tools::CLI;
and a module file in MyApp/Tools called CLI.pm6:
#PROCESS::<%SUB-MAIN-OPTS><named-anywhere> = True;
my %*SUB-MAIN-OPTS = :named-anywhere;
proto MAIN(|) is export {*}
multi MAIN( 'add', :h( :$hostnames ) ) {
for #$hostnames -> $host {
say $host;
}
}
multi MAIN( 'remove', *#hostnames ) {
for #hostnames -> $host {
say $host;
}
}
The following invocation from the command line will not result in a recognized subroutine, but show the usage:
mre.raku add -h=localhost -h=test1
Switching my %*SUB-MAIN-OPTS = :named-anywhere; for PROCESS::<%SUB-MAIN-OPTS><named-anywhere> = True; will print two lines with the two hostnames provided, as expected.
If however, this is done in a single file as below, both work identical:
#!/usr/bin/env raku
#PROCESS::<%SUB-MAIN-OPTS><named-anywhere> = True;
my %*SUB-MAIN-OPTS = :named-anywhere;
proto MAIN(|) is export {*}
multi MAIN( 'add', :h( :$hostnames )) {
for #$hostnames -> $host {
say $host;
}
}
multi MAIN( 'remove', *#hostnames ) {
for #hostnames -> $host {
say $host;
}
}
I find this hard to understand.
When reproducing this, be alert of how each command must be called.
mre.raku remove localhost test1
mre.raku add -h=localhost -h=test1
So a named array-reference is not recognized when this is used in a separate file with my %*SUB-MAIN-OPTS = :named-anywhere;. While PROCESS::<%SUB-MAIN-OPTS><named-anywhere> = True; always works. And for a slurpy array, both work identical in both cases.

The problem is that it isn't the same variable in both the script and in the module.
Sure they have the same name, but that doesn't mean much.
my \A = anon class Foo {}
my \B = anon class Foo {}
A ~~ B; # False
B ~~ A; # False
A === B; # False
Those two classes have the same name, but are separate entities.
If you look at the code for other built-in dynamic variables, you see something like:
Rakudo::Internals.REGISTER-DYNAMIC: '$*EXECUTABLE-NAME', {
PROCESS::<$EXECUTABLE-NAME> := $*EXECUTABLE.basename;
}
This makes sure that the variable is installed into the right place so that it works for every compilation unit.
If you look for %*SUB-MAIN-OPTS, the only thing you find is this line:
my %sub-main-opts := %*SUB-MAIN-OPTS // {};
That looks for the variable in the main compilation unit. If it isn't found it creates and uses an empty Hash.
So when you try do it in a scope other than the main compilation unit, it isn't in a place where it could be found by that line.
To test if adding that fixes the issue, you can add this to the top of the main compilation unit. (The script that loads the module.)
BEGIN Rakudo::Internals.REGISTER-DYNAMIC: '%*SUB-MAIN-OPTS', {
PROCESS::<%SUB-MAIN-OPTS> := {}
}
Then in the module, write this:
%*SUB-MAIN-OPTS = :named-anywhere;
Or better yet this:
%*SUB-MAIN-OPTS<named-anywhere> = True;
After trying this, it seems to work just fine.
The thing is, that something like that used to be there.
It was removed on the thought that it slows down every Raku program.
Though I think that any slowdown it caused would still be an issue as the line that is still there has to look to see if there is a dynamic variable of that name.
(There are more reasons given, and I frankly disagree with all of them.)

May a cuppa bring enlightenment to future SO readers pondering the meaning of things.[1]
Related answers by Liz
I think Liz's answer to an SO asking a similar question may be a good read for a basic explanation of why a my (which is like a lesser our) in the mainline of a module doesn't work, or at least confirmation that core devs know about it.
Her later answer to another SO explains how one can use my by putting it inside a RUN-MAIN.
Why does a slurpy array work by default but not named anywhere?
One rich resource on why things are the way they are is the section Declaring a MAIN subroutine of S06 (Synopsis on Subroutines)[2].
A key excerpt:
As usual, switches are assumed to be first, and everything after the first non-switch, or any switches after a --, are treated as positionals or go into the slurpy array (even if they look like switches).
So it looks like this is where the default behavior, in which nameds can't go anywhere, comes from; it seems that #Larry[3] was claiming that the "usual" shell convention was as described, and implicitly arguing that this should dictate that the default behavior was as it is.
Since Raku was officially released RFC: Allow subcommands in MAIN put us on the path to todays' :named-anywhere option. The RFC presented a very powerful 1-2 punch -- an unimpeachable two line hackers' prose/data argument that quickly led to rough consensus, with a working code PR with this commit message:
Allow --named-switches anywhere in command line.
Raku was GNU-like in that it has '--double-dashes' and that it stops interpreting named parameters when it encounters '--', but unlike GNU-like parsing, it also stopped interpreting named parameters when encountering any positional argument. This patch makes it a bit more GNU-like by allowing named arguments after a positional, to prepare for allowing subcommands.
> Alter how arguments are processed before they're passed to sub MAIN
In the above linked section of S06 #Larry also wrote:
Ordinarily a top-level Raku "script" just evaluates its anonymous mainline code and exits. During the mainline code, the program's arguments are available in raw form from the #*ARGS array.
The point here being that you can preprocess #*ARGS before they're passed to MAIN.
Continuing:
At the end of the mainline code, however, a MAIN subroutine will be called with whatever command-line arguments remain in #*ARGS.
Note that, as explained by Liz, Raku now has a RUN-MAIN routine that's called prior to calling MAIN.
Then comes the standard argument processing (alterable by using standard options, of which there's currently only the :named-anywhere one, or userland modules such as SuperMAIN which add in various other features).
And finally #Larry notes that:
Other [command line parsing] policies may easily be introduced by calling MAIN explicitly. For instance, you can parse your arguments with a grammar and pass the resulting Match object as a Capture to MAIN.
A doc fix?
Yesterday you wrote a comment suggesting a doc fix.
I now see that we (collectively) know about the coding issue. So why is the doc as it is? I think the combination of your SO and the prior ones provide enough anecdata to support at least considering filing a doc issue to the contrary. Then again Liz hints in one of the SO's that a fix might be coming, at least for ours. And SO is itself arguably doc. So maybe it's better to wait? I'll punt and let you decide. At least you now have several SOs to quote if you decide to file a doc issue.
Footnotes
[1] I want to be clear that if anyone perceives any fault associated with posting this SO then they're right, and the fault is entirely mine. I mentioned to #acw that I'd already done a search so they could quite reasonably have concluded there was no point in them doing one as well. So, mea culpa, bad coffee inspired puns included. (Bad puns, not bad coffee.)
[2] Imo these old historical speculative design docs are worth reading and rereading as you get to know Raku, despite them being obsolete in parts.
[3] #Larry emerged in Raku culture as a fun and convenient shorthand for Larry Wall et al, the Raku language team led by Larry.

Related

Documentation for the object Signature: " ... different name for a named argument than the variable name"

An example on the 'class Signature' page appears as:
sub named(:official($private)) { "Official business!" if $private }; named :official;
<-----
Note: That's where to example ends ... there is no output described or shown.
So I typed in the code and when the method 'named' is executed it always prints "Official business!" no matter the value of $private. That is, if $private=True then invoking 'named' prints "Official business!" as you might expect but with $private=False invoking 'named' still prints 'Official business!' whereas I thought there should be no output generated. I'm missing something aren't I but what?
There are a couple of things going on in this short example:
sub named(:official($private)) { "Official business!" if $private }
-------- --------
| |
| > '$private' is the name of this var within the sub
|
> 'official' is the (sigilless) name of this var outside
------------------
|
> ':official($private)' is the
raku Pair 'official => $private'
named :official
----- ---------
| |
| > the raku Pair 'official => True' (so $private ~~ True)
|
> the same as 'named( official => True );'
So when you try this in the repl...
> named :official; #Official business!
> named( official => True ) #Official business! [same thing]
-or-
> named :!official #()
> named( official => False ) #() [same thing]
At first encounter, in this example, raku is quite quirky. Why?
the raku Pair literal syntax makes it easy to handle common function argument cases such as :dothis but :!notthat adverbs
the :name(value) formulation is re-used here to map external to internal var names - nothing special needed since the Pair syntax already does it - but super useful for code encapsulation
similar situation with argument aliases ... you can think of this as Pairs of Pairs ... again, no special syntax needed since just using the built in Pair literal syntax
So, imho, raku is uniquely cool in that we just have to learn some basic elemental syntax (in this case, the Pair literals) and then they can be applied consistently in many ways to concisely solve quite thorny coding scenarios.
I see how the doc example was confusing. Here's an expanded version of that explanation:
sub named(:official($private)) {
# Inside the function, the argument the caller passed in
# is bound to the variable $private. Nothing is bound to official.
say $private;
}
# Outside the function, the caller doesn't need to care what term the
# function uses. All it needs to know is the name of the parameter – :official
named(:official('foo')); # OUTPUT: «foo»
This is especially handy when the function is in a different module – the owner of the function can refactor the name of the their $private argument without breaking any external callers. And, if they think of a better name for external callers to use, they can even add that without breaking backwards compatibility: sub named(:official(:better-name(:$private))) { … } lets callers use either :official or :better-name as the parameter name, without having any impact on the variable name inside the function.
Does that make more sense?
Oh, and one note regarding this:
if $private=True then invoking 'named' prints "Official business!" as you might expect
If I'm understanding you correctly, you mean writing something like
sub named(:official($private)=True) { "Official business!" if $private }
Is that what you meant? If so, you should know that $private=True in that signature isn't really setting $private to anything – it's just providing a default value for the variable $private. So you can get this output:
sub named(:official($private)=True) {
say $private;
}
named(); # OUTPUT: «True»
named(:official(42)); # OUTPUT: «42»
In any event, I'll send in a PR to the docs repo and try to clarify the named argument examples a bit. Hope you enjoy Raku!
Via pretzel logic I've concluded that:
You may have carefully written your Q to trick us, and you will reveal the truth if we correctly solve the riddle.
Or (a tad more likely perhaps... 🤡):
Adopting that mindset will help us all -- you, readers, answerers -- have fun as we try to solve the riddle inherent in your sincere Q even if you weren't planning to make this fun...
Either way, please read this answer and let me know if it contributes to solving the riddle. TIA. :)
I'm missing something aren't I but what?
Perhaps this is a key for solving the riddle: we're supposed to ask ourselves "What has Keith deliberately missed out of the Q?".
Of course, if this is so, the first thing you've omitted is that it's a riddle. In which case, major kudos! And if it's not an intentional riddle, well, it's still a riddle, so kudos anyway, and let's try solve it!
#codesection's answer points at perhaps the strongest clue. While you didn't write a minimal reproducible example, you did write the sub definition code, and you did say you'd written $private=False.
So let's presume you literally wrote that sub definition and you literally wrote $private=False.
Furthermore, that:
with $private=False invoking 'named' still prints 'Official business!' whereas I thought there should be no output generated.
means there was some output generated in all cases.
Anyhoo, how can all of these things be true at the same time?
These are compile-time errors:
sub named( :official( $private = True ) ) { "Official business!" if $private }
sub named( :official( $private = False ) ) { "Official business!" if $private }
So is this:
$private = False;
unless there was a prior my $private....
And this:
sub named( :official( $private ) ) {
$private = True;
"Official business!" if $private
}
named;
yields Cannot assign to a readonly variable or a value (currently at runtime) because, by default, parameters to routines are readonly.
You also said there was output (ostensibly Official business!, but perhaps sometimes something else, eg ()?).
You didn't mention a say or similar routine for displaying output. How could that be? Let's introduce a say.
So, putting these things together, and applying pretzel logic, I arrived here:
sub named(:official($private)) { "Official business!" if $private }
my $private;
$private = False;
say named :official; # Official business!
say named :!official; # ()
say named official => False; # ()
say named :official(False); # ()
say named; # ()
An interpretation of this as solving the riddle:
() is not "no output". So it doesn't contradict your Q narrative.
We've written $private = False. It has no impact on the code, because of lexical scoping, but we did write it. :)
Am I warm?
Dear kind and generous raku folk,
Thank you for the replies and discourse. After which I now understand what I didn't understand. And the root of my misunderstanding started here: At the time of writing this, the doc page for class Pair says:
There are many syntaxes for creating Pairs
and goes on to give examples, one of which is this line:
:foo(127) # short for foo => 127
So I thought in the raku interactive environment that these two lines:
> :foo(127)
foo => 127
> :foo.kv
(foo True)
Would answer (foo 127) for the last line. However sadly, no, the answer is (foo True)
But I didn't know that when I went off to read the 'Class Signature' page and got into a pickle with the example:
sub named(:official($private));
named :official
Which now appears to be a truncated example.
And sent me off on a tangent thinking there was lot of magic in what a colon can do.
Anyway, I hope everyone is keeping well ... see you later alligators.

Separating operator definitions for a class to other files and using them

I have 4 files all in the same directory: main.rakumod, infix_ops.rakumod, prefix_ops.rakumod and script.raku:
main module has a class definition (class A)
*_ops modules have some operator routine definitions to write, e.g., $a1 + $a2 in an overloaded way.
script.raku tries to instantaniate A object(s) and use those user-defined operators.
Why 3 files not 1? Since class definition might be long and separating overloaded operator definitions in files seemed like a good idea for writing tidier code (easier to manage).
e.g.,
# main.rakumod
class A {
has $.x is rw;
}
# prefix_ops.rakumod
use lib ".";
use main;
multi prefix:<++>(A:D $obj) {
++$obj.x;
$obj;
}
and similar routines in infix_ops.rakumod. Now, in script.raku, my aim is to import main module only and see the overloaded operators also available:
# script.raku
use lib ".";
use main;
my $a = A.new(x => -1);
++$a;
but it naturally doesn't see ++ multi for A objects because main.rakumod doesn't know the *_ops.rakumod files as it stands. Is there a way I can achieve this? If I use prefix_ops in main.rakumod, it says 'use lib' may not be pre-compiled perhaps because of circular dependentness
it says 'use lib' may not be pre-compiled
The word "may" is ambiguous. Actually it cannot be precompiled.
The message would be better if it said something to the effect of "Don't put use lib in a module."
This has now been fixed per #codesections++'s comment below.
perhaps because of circular dependentness
No. use lib can only be used by the main program file, the one directly run by Rakudo.
Is there a way I can achieve this?
Here's one way.
We introduce a new file that's used by the other packages to eliminate the circularity. So now we have four files (I've rationalized the naming to stick to A or variants of it for the packages that contribute to the type A):
A-sawn.rakumod that's a role or class or similar:
unit role A-sawn;
Other packages that are to be separated out into their own files use the new "sawn" package and does or is it as appropriate:
use A-sawn;
unit class A-Ops does A-sawn;
multi prefix:<++>(A-sawn:D $obj) is export { ++($obj.x) }
multi postfix:<++>(A-sawn:D $obj) is export { ($obj.x)++ }
The A.rakumod file for the A type does the same thing. It also uses whatever other packages are to be pulled into the same A namespace; this will import symbols from it according to Raku's standard importing rules. And then relevant symbols are explicitly exported:
use A-sawn;
use A-Ops;
sub EXPORT { Map.new: OUTER:: .grep: /'fix:<'/ }
unit class A does A-sawn;
has $.x is rw;
Finally, with this setup in place, the main program can just use A;:
use lib '.';
use A;
my $a = A.new(x => -1);
say $a++; # A.new(x => -1)
say ++$a; # A.new(x => 1)
say ++$a; # A.new(x => 2)
The two main things here are:
Introducing an (empty) A-sawn package
This type eliminates circularity using the technique shown in #codesection's answer to Best Way to Resolve Circular Module Loading.
Raku culture has a fun generic term/meme for techniques that cut through circular problems: "circular saws". So I've used a -sawn suffix of the "sawn" typename as a convention when using this technique.[1]
Importing symbols into a package and then re-exporting them
This is done via sub EXPORT { Map.new: ... }.[2] See the doc for sub EXPORT.
The Map must contain a list of symbols (Pairs). For this case I've grepped through keys from the OUTER:: pseudopackage that refers to the symbol table of the lexical scope immediately outside the sub EXPORT the OUTER:: appears in. This is of course the lexical scope into which some symbols (for operators) have just been imported by the use Ops; statement. I then grep that symbol table for keys containing fix:<; this will catch all symbol keys with that string in their name (so infix:<..., prefix:<... etc.). Alter this code as needed to suit your needs.[3]
Footnotes
[1] As things stands this technique means coming up with a new name that's different from the one used by the consumer of the new type, one that won't conflict with any other packages. This suggests a suffix. I think -sawn is a reasonable choice for an unusual and distinctive and mnemonic suffix. That said, I imagine someone will eventually package this process up into a new language construct that does the work behind the scenes, generating the name and automating away the manual changes one has to make to packages with the shown technique.
[2] A critically important point is that, if a sub EXPORT is to do what you want, it must be placed outside the package definition to which it applies. And that in turn means it must be before a unit package declaration. And that in turn means any use statement relied on by that sub EXPORT must appear within the same or outer lexical scope. (This is explained in the doc but I think it bears summarizing here to try head off much head scratching because there's no error message if it's in the wrong place.)
[3] As with the circularity saw aspect discussed in footnote 1, I imagine someone will also eventually package up this import-and-export mechanism into a new construct, or, perhaps even better, an enhancement of Raku's built in use statement.
Hi #hanselmann here is how I would write this (in 3 files / same dir):
Define my class(es):
# MyClass.rakumod
unit module MyClass;
class A is export {
has $.x is rw;
}
Define my operators:
# Prefix_Ops.rakumod
unit module Prefix_Ops;
use MyClass;
multi prefix:<++>(A:D $obj) is export {
++$obj.x;
$obj;
}
Run my code:
# script.raku
use lib ".";
use MyClass;
use Prefix_Ops;
my $a = A.new(x => -1);
++$a;
say $a.x; #0
Taking my cue from the Module docs there are a couple of things I am doing different:
Avoiding the use of main (or Main, or MAIN) --- I am wary that MAIN is a reserved name and just want to keep clear of engaging any of that (cool) machinery
Bringing in the unit module declaration at the top of each 'rakumod' file ... it may be possible to use bare files in Raku ... but I have never tried this and would say that it is not obvious from the docs that it is even possible, or supported
Now since I wanted this to work first time you will note that I use the same file name and module name ... again it may be possible to do that differently (multiple modules in one file and so on) ... but I have not tried that either
Using the 'is export' trait where I want my script to be able to use these definitions ... as you will know from close study of the docs ;-) is that each module has it's own namespace (the "stash") and we need export to shove the exported definitions into the namespace of the script
As #raiph mentions you only need the script to define the module library location
Since you want your prefix multi to "know" about class A then you also need to use MyClass in the Prefix_Ops module
Anyway, all-in-all, I think that the raku module system exemplifies the unique combination of "easy things easy and hard thinks doable" ... all I had to do with your code (which was very close) was tweak a few filenames and sprinkle in some concise concepts like 'unit module' and 'is export' and it really does not look much different since raku keeps all the import/export machinery under the surface like the swan gliding over the river...

SLICC indexing syntax

I have been digging through the cache-related parts of Gem5 (particularly the parts related to directories), and I've hit a bit of a snag.
This is the code for getDirectoryEntry(Addr addr), in src/mem/ruby/protocol/MESI_Two_Level-dir.sm:
Entry getDirectoryEntry(Addr addr), return_by_pointer="yes" {
Entry dir_entry := static_cast(Entry, "pointer", directory[addr]);
if (is_valid(dir_entry)) {
return dir_entry;
}
dir_entry := static_cast(Entry, "pointer",
directory.allocate(addr, new Entry));
return dir_entry;
}
Note the first line inside the function, where it says directory[addr].
directory was previously defined like so:
machine(MachineType:Directory, "MESI Two Level directory protocol")
: DirectoryMemory * directory;
...
I am trying to understand exactly what that directory[addr] bit of code means. Intuitively, it may be calling the C++ DirectoryMemory::lookup(Addr address) method, but I haven't found any code or documentation that supports that guess.
The DirectoryMemory class doesn't define an indexing operator, and there's also nothing in the SLICC page on the wiki that describes an indexing operator.
tl;dr: what does the indexing operator mean in SLICC? It it's defined for particular objects somewhere in the SLICC code, what should I be looking for to find its definition?
Thanks in advance!
Figured it out myself. It calls the lookup method in DirectoryMemory, as I suspected.

Changing $*DISTRO values for testing

I need to test a feature that includes this line:
if $translate-nl && $*DISTRO.is-win
I have tried to reassign a value to $*DISTRO,
$*DISTRO='Windows 10';
but it says:
Cannot modify an immutable Distro (debian (9.stretch))␤
$*DISTRO is a dynamic variable, and it makes sense that it's not modified. That said, is there any other way that code can be tested (other than going to Windows, of course)
my $*DISTRO = ...
Hopefully modifying the original is unnecessary. It's generally unreasonable action-at-a-distance -- almost certainly so if someone has arranged for it to be an immutable value. This is the reason why global variables got such a bad reputation.
To elaborate on raiph's answer: the * in $*DISTRO marks it as a dynamic variable. You can re-declare it any scope, and code called from there will see the redeclared value:
{
my $*DISTRO = ...;
# coded called from here sees the redeclared value
}
# code called from here sees the original value
Now, the question remains, what do you put in place of these pesky ...?
In the simplest case, a mock that just has whatever the code under test needs:
{
my class Distro { has $.is-win }
my $*DISTRO = Distro.new( :is-win );
# call your test code here
}
If the code needs more attributes in Distro, just add them to the mock Distro class.
If the code needs a "real* Distro object, for some reason, you can instantiate the built-in one. The constructor .new isn't really documented, but the source code makes it pretty obvious what arguments it expects.
OK, I got the answer relatively fast. $*DISTRO is actually a read-only alias of PROCESS::<$DISTRO>
So we only need to do:
my $*DISTRO = Distro.new(:is-win,:release<11>,:path-sep('|||'),:auth<unknown>,:name<mswin32>,:desc<Test>,:version<v11>);
say $*DISTRO.is-win; #OUTPUT: «True␤»

Using a variable in a Perl 6 program before assigning to it

I want to assign literals to some of the variables at the end of the file with my program, but to use these variables earlier. The only method I've come up with to do it is the following:
my $text;
say $text;
BEGIN {
$text = "abc";
}
Is there a better / more idiomatic way?
Just go functional.
Create subroutines instead:
say text();
sub text { "abc" }
UPDATE (Thanks raiph! Incorporating your feedback, including reference to using term:<>):
In the above code, I originally omitted the parentheses for the call to text, but it would be more maintainable to always include them to prevent the parser misunderstanding our intent. For example,
say text(); # "abc"
say text() ~ text(); # "abcabc"
say text; # "abc", interpreted as: say text()
say text ~ text; # ERROR, interpreted as: say text(~text())
sub text { "abc" };
To avoid this, you could make text a term, which effectively makes the bareword text behave the same as text():
say text; # "abc", interpreted as: say text()
say text ~ text; # "abcabc", interpreted as: say text() ~ text()
sub term:<text> { "abc" };
For compile-time optimizations and warnings, we can also add the pure trait to it (thanks Brad Gilbert!). is pure asserts that for a given input, the function "always produces the same output without any additional side effects":
say text; # "abc", interpreted as: say text()
say text ~ text; # "abcabc", interpreted as: say text() ~ text()
sub term:<text> is pure { "abc" };
Unlike Perl 5, in Perl 6 a BEGIN does not have to be a block. However, the lexical definition must be seen before it can be used, so the BEGIN block must be done before the say.
BEGIN my $text = "abc";
say $text;
Not sure whether this constitutes an answer to your question or not.
First, a rephrase of your question:
What options are there for succinctly referring to a variable (or constant etc.) whose initialization code appears further down in the same source file?
Post declare a routine
say foo;
sub foo { 'abc' }
When a P6 compiler parses an identifier that has no sigil, it checks to see if it has already seen a declaration of that identifier. If it hasn't, then it assumes that the identifier corresponds to a routine which will be declared later as a "listop" routine (which takes zero or more arguments) and moves on. (If its assumption turns out to be wrong, it fails the compilation.)
So you can use routines as if they were variables as described in Christopher Bottom's answer.
Autodeclare a variable on first use
strict is a "pragma" that controls how a P6 compiler reacts when it parses an as yet undeclared variable/constant that starts with a sigil.
P6 starts programs with strict mode switched on. This means that the compiler will insist on predeclaration of any sigil'd variable/constant. (By predeclaration I mean an explicit declaration that appears textually before the variable/constant is used.)
But you can write use strict or no strict to control whether the strict pragma is on or off in a given lexical scope, so this will work:
no strict;
say $text;
BEGIN {
$text = "abc";
}
Warning Having no strict in effect (which is unfortunately how most programming languages work) makes accidental misspelling of variable names a bigger nuisance than it is with use strict mode on.
Declare a variable explicitly in the same statement as its first use
You don't have to write a declaration as a separate statement. You can instead declare and use a variable in the same statement or expression:
say my $text;
BEGIN {
$text = "abc";
}
Warning If you repeat my $bar in the exact same lexical scope, the compiler will emit a warning. In contrast, say my $bar = 42; if foo { say my $bar = 99 } creates two distinct $bar variables without warning.
Initialize at run-time
The BEGIN phaser shown above runs at compile-time (after the my declaration, which also happens at compile-time, but before the say, which happens at run-time).
If you want to initialize variables/constants at run-time instead, use INIT instead:
say my $text;
INIT {
$text = "abc";
}
INIT code runs before any other run-time code, so the initialization still happens before the say gets executed.
Use a positronic (ym) variable
Given a literal interpretation of your question a "positronic" or ym variable would be yet another solution. (This feature is not built-in. I'm including it mostly because I encountered it after answering this question and think it belongs here, at the very least for entertainment value.)
Initialization and calculation of such a variable starts in the last statement using it and occurs backwards relative to the textual order of the code.
This is one of the several crazy sounding but actually working and useful concepts that Damian "mad scientist" Conway discusses in his 2011 presentation Temporally Quaquaversal Virtual Nanomachine Programming In Multiple Topologically Connected Quantum-Relativistic Parallel Spacetimes... Made Easy!.
Here's a link to the bit where he focuses on these variables.
(The whole presentation is a delight, especially if you're interested in physics; programming techniques; watching highly creative wunderkinds; and/or enjoy outstanding presentation skills and humor.)
Create a PS pragma?
In terms of coolness, the following pales in comparison to Damian's positronic variable feature that I just covered, but it's an idea I had while pondering this question.
Someone could presumably implement something like the following pragma:
use PS;
say $text;
BEGIN $text = 'abc';
This PS would lexically apply no strict and in addition require that, to avoid a compile-time error:
An auto-declared variable/constant must match up with a post declaration in a BEGIN or INIT phaser;
The declaration must include initialization if the first use (textually) of a variable/constant is not a binding or assignment.