Frequently asked questions about Raku™
Properly speaking, Rakudo is an implementation of Raku. It's currently the one that's being developed, but there have been other implementations in the past and there will likely be others in the future. Raku is the definition of the language. When talking about the current interpreter, Rakudo and Raku can be used interchangeably. "Perl 6" is the name that was used for "Raku" before October 2019.
The Rakudo 2015.12 implementation version was released on December 25th 2015, which implemented the v6.c Raku specification, released at the same time.
No. The first stable language specification version is v6.c ("Christmas"). Future versions of the spec may have point releases (e.g., v6.d.2) or major releases (e.g., v6.e).
Running raku -v
will display the language version your compiler implements, e.g.:
$ raku -vWelcome to Rakudo™ v2022.04.Implementing the Raku® Programming Language v6.d.Built on MoarVM version 2022.04.
The v6.d Specification was released on Diwali 2018, which was November 6–7 2018, in a convenient time zone. 6.d was enabled by default in the Rakudo compiler release of 2018.11.
The vast majority of 6.d features were already implemented and available in the Rakudo compiler without requiring any special pragmas, as they did not conflict with the 6.c specification. A smaller set of features and behaviors is available automatically if you have the use v6.d
pragma at the top of the file. The rest of about 3100 new commits to the language specification simply clarify previously undefined behavior.
Mac users can use the latest Rakudo Star DMG binary installer at https://rakudo.org/downloads/star
Windows users can use the Rakudo Star MSI binary installer. You will need Windows Git and Strawberry Perl to use zef to install library modules.
Linux users probably want to download Rakudo Star and follow the compilation instructions at https://www.raku.org/downloads/.
There should be Linux and Mac binaries available from vendors and third parties, although vendor versions may be outdated. Versions before Rakudo release of 2015.12 should be avoided.
There's an official Rakudo Star docker image at https://hub.docker.com/_/rakudo-star/
An option is to clone the repository and build it. This will install work in progress which is minimally-tested and may contain severe bugs. If you're interested in contributing to the Rakudo Raku compiler, you may find the Z-Script helper tool useful.
To install the last official monthly release, check out the tag visible at https://raw.githubusercontent.com/rakudo/rakudo/master/VERSION or set up a helper command.
Some users choose to use rakubrew, which allows quick installation of multiple versions of Rakudo in parallel.
In either case you will probably need to also install zef
and p6doc
from the ecosystem.
See the official documentation website (especially its "Language" section) as well as the Resources page. You can also consult this great cheatsheet.
perl6book.com contains a list of dead tree and electronic books.
Be mindful of publication dates when reading third-party articles. Anything published before December, 2015 likely describes a pre-release version of Raku.
You can always get help from a live human in our help chat or search the chat logs to find previous conversations and discussions.
Here are some available books, in alphabetical order:
Learning Raku, by brian d foy
Learning to program with Raku: First Steps, by JJ Merelo
Metagenomics, by Ken Youens-Clark
Parsing with Perl 6 Regexes and Grammars, by Moritz Lenz
Perl 6 at a Glance, by Andrew Shitov
Raku Fundamentals, by Moritz Lenz
Perl 6 Deep Dive, by Andrew Shitov
Think Perl 6: How to Think Like a Computer Scientist, by Laurent Rosenfeld.
A list of books published or in progress is maintained in Resources page.
The specification refers to the official test suite for Raku. It's called roast
and is hosted on github. Any compiler that passes the tests is deemed to implement that version of the Raku specification.
Roast's master
branch corresponds to the latest development that isn't necessarily part of any specification yet. Other branches correspond to specific versions; for example, "6.c-errata".
So 6.c-errata
is a released language version we don't change other than to fix errors in tests (the "errata") whereas master is the unreleased work-in-progress that may become the next language version. Its current state is not necessarily prescriptive of the next language version's behavior since new additions will be reviewed for inclusion into the release.
Yes, see glossary.
There are several Perl to Raku guides in the "Language" section, most notable of which is the Overview.
See the rb-nutshell guide.
Yes. As a user, the zef
module installer will automatically install the version of a module with the highest version number. If you want a specific version and/or a version from a specific author, you can also specify that with zef
.
As a new module author, you can use the fez
module uploader to upload your module to the Raku ecosystem. There are also a number of helper modules that help you set up a skeleton of a distribution, such as App::Mi6
, which will also help you with uploading once your module is ready for distribution.
Historically, you could also upload a Raku module to CPAN by using PAUSE to upload a module. And before that, there was a way of using Github/Gitlab to make your module available for download. These are now considered to not be the best way for new module authors to start with.
Yes, it's called p6doc
and is present in the ecosystem under that name. It comes bundled in with Rakudo Star but needs to be manually installed with zef
if you are using a Rakudo monthly release.
Yes, with Inline::Perl5, which works well with most Perl modules. It can even run Perl Catalyst and DBI.
Nativecall makes this particularly easy.
libfoo.so
and I only have libfoo.so.1.2
!In most Linux systems, shared libraries will be installed in such a way that, for a specific libfoo
, there will be a libfoo.so.x.y.z
real file, and then a set of symlinks libfoo.so
and libfoo.so.x
. for instance, ls /usr/local/lib/libxxhash.so*
returns:
/usr/local/lib/libxxhash.so -> libxxhash.so.0.6.5/usr/local/lib/libxxhash.so.0 -> libxxhash.so.0.6.5/usr/local/lib/libxxhash.so.0.6.5
In general, installing a libfoo-dev
or libfoo-devel
(depending on the distro) in Linux will install the shared library and set up those symlinks for you. But in some cases, you will only have, as in the question, libfoo.so.1.2
.
In that case, just use the version of is native
that explicitly sets the ABI/API version, as indicated in the manual:
sub call-foo() is native('foo',v1.2);
It's fairly easy to use Nativecall to access them.
An ecosystem module POSIX is also available.
Rakudo Star distribution does come with many useful modules.
Rakudo compiler-only release includes only a couple of the most basic modules.
Many more modules can be found in the ecosystem.
B::Deparse
/How can I get hold of the AST?Use --target=optimize
command line option to view the AST of your program, e.g., raku --target=optimize -e 'say "hi"'
The target optimize
gives the AST after the static optimizer does its job, while target ast
gives the AST before that step. To get the full list of available targets, run raku --stagestats -e ""
When you load a module for the first time, Rakudo compiles it into bytecode. Then, Rakudo both stores the compiled bytecode on disk and uses it, because that tends to be significantly faster.
No, you can't have circular dependencies, and you should get a Circular module loading detected
error if you have them between your modules.
Very likely you can accomplish what you are trying to do using roles. Instead of A.rakumod
depending on B.rakumod
and B.rakumod
depending on A.rakumod
, you can have A-Role.rakumod
and B-Role.rakumod
and classes in A.rakumod
and B.rakumod
implementing these roles respectively. Then you can depend on A-Role.rakumod
and B-Role.rakumod
without the need for the circular dependency.
One of the reasons why circular dependencies do not work in Raku is one pass parsing. We have to know what A means when we parse B, and we have to know what B means when we parse A, which is clearly an infinite loop.
Note that Raku has no “1 file = 1 class” limitation, and circular dependencies within a single compilation unit (e.g., file) are possible through stubbing. Therefore another possible solution is to move classes into the same compilation unit.
Use the + prefix:
say "42.123456789123456789"; # OUTPUT: «42.123456789123456789»say +"42.4e-2"; # OUTPUT: «0.424»
This example of contextualization can numify any string you could enter as a literal number. val routine converts it to allomorph. unival routine converts one unicode codepoint.
"az and az and az again".contains("az"); # OUTPUT: «True»"az and az and az again".indices("az"); # OUTPUT: «(0 7 14)»
To get a hexadecimal list of each byte of a string (i.e. hex encoder), first convert the string to a Blob with .encode.
say "I ❤ 🦋".encode>>.base(16); # OUTPUT: «(49 20 E2 9D A4 20 F0 9F A6 8B)»
Note that .gist or .raku methods can be useful for variable introspection:
say "I ❤ 🦋".encode.raku; # OUTPUT: «utf8.new(73,32,226,157,164,32,240,159,166,139)»say "I ❤ 🦋".encode.gist; # OUTPUT: «utf8:0x<49 20 E2 9D A4 20 F0 9F A6 8B>»
Use .comb to transform it to a Seq, then the (-) infix to remove the unwanted indices:
say '0123456789'.comb[(^* (-) (1..3, 8).flat).keys.sort].join; # OUTPUT: «045679»
If the string is large, .comb can take time. In which case, .substr-rw is faster:
multi postcircumfix:<[- ]> (Str is copy, +)say '0123456789'[- 1..3, 8 ]; # OUTPUT: «045679»
.comb is accepting an optional Int:
.say for 'abcdefghijklmnopqrstuvwxyz'.comb: 8; # OUTPUT: «abcdefghijklmnopqrstuvwxyz»
Typical options are to use the say routine that uses the .gist method which gives the "gist" of the object being dumped. More detailed output can be obtained by calling the perl method (soon to be deprecated in favor of $obj.raku
, available since the Rakudo 2019.11 release) that typically returns an object's representation in EVAL-able code.
If you're using the rakudo implementation, you can use the rakudo-specific dd
routine for dumping, whose output is similar to .raku, but with more information.
Examples:
my = %( foo => 'bar' );say .raku; # OUTPUT: «${:foo("bar")}»say ; # OUTPUT: «{foo => bar}»# non-standard routine available in rakudo implementation:dd ; # OUTPUT: «Hash $foo = ${:foo("bar")}»
There are also several ecosystem modules that provide more control over how data structures are dumped, including support for colored output.
Install Linenoise from the ecosystem.
An alternative for UNIX-like systems is to install rlwrap
. This can be done on Debian-ish systems by running:
sudo apt-get install rlwrap
If SORRY! is present in the output, the error is a compile time error. Otherwise, it's a runtime error.
Example:
sub foo( Int , Int )foo(1) # ===SORRY!=== Error while compiling ...
say 1/0; # Attempt to divide 1 by zero using div
(Any)
?Any
is a top level class most objects inherit from. The Any
type object is the default value on variables and parameters without an explicit type constraint, which means you'll likely see (Any)
printed when you output a .gist of a variable without any value by using, for instance, the say:
my ;say ; # OUTPUT: «(Any)»my Int ;say ; # OUTPUT: «(Int)»my = 70;say ; # OUTPUT: «70»
To test whether a variable has any defined values, see DEFINITE and defined routines. Several other constructs exist that test for definiteness, such as with
, orwith
, and without
statements, //
, andthen, notandthen, and orelse operators, as well as type constraint smileys.
so
?so
is a loose precedence operator that coerces to Bool.
It has the same semantics as the ?
prefix operator, just like and
is the low-precedence version of &&
.
Example:
say so 1|2 == 2; # OUTPUT: «True»
In this example, the result of the comparison (which is a Junction), is converted to Bool before being printed.
:D
and :U
things in signatures?In Raku, classes and other types are objects and pass type checks of their own type.
For example, if you declare a variable
my Int = 42;
then not only can you assign integers (that is, instances of class Int) to it, but the Int
type object itself:
= Int
If you want to exclude type objects, you can append the :D
type smiley, which stands for "definite":
my Int = 42;= Int;# dies with:# Type check failed in assignment to $x;# expected Int:D but got Int
Likewise, :U
constrains to undefined values, that is, type objects.
To explicitly allow either type objects or instances, you can use :_
.
-->
thing in the signature?--> is a return constraint, either a type or a definite value.
Example of a type constraint:
sub divide-to-int( Int , Int --> Int )divide-to-int(3, 2)# Type check failed for return value; expected Int but got Rat
Example of a definite return value:
sub discard-random-number( --> 42 )say discard-random-number;# OUTPUT: «42»
In this case, the final value is thrown away because the return value is already specified in the signature.
If you want to extract the values (eigenstates) from a Junction, you are probably doing something wrong and should be using a Set instead.
Junctions are meant as matchers, not for doing algebra with them.
If you want to do it anyway, you can abuse autothreading for that:
sub eigenstates(Mu )say eigenstates(1|2|3).join(', ');# prints 1, 2, 3 or a permutation thereof
s///
work? If Int is immutable, how does $i++
work?In Raku, values of many basic types are immutable, but the variables holding them are not. The s///
operator works on a variable, into which it puts a newly created string object. Likewise, $i++
works on the $i
variable, not just on the value in it.
Knowing this, you would not try to change a literal string (e.g. like 'hello' ~~ s/h/H/;
), but you might accidentally do something equivalent using map
as follows.
my = <hello world>.map: ;# dies with# Cannot modify an immutable Str (hello)my = <hello world>».subst-mutate: 'h', 'H';# dies with# Cannot resolve caller subst-mutate(Str: Str, Str);# the following candidates match the type but require# mutable arguments: ...
Instead of modifying the original value in place, use a routine or operator that returns a new value:
my = <hello world>.map: ; # ['Hello','world']my = <hello world>».subst: 'h', 'H'; # ['Hello','world']
See the documentation on containers for more information.
@
sigil?In Raku, nearly everything is a reference, so talking about taking references doesn't make much sense. Scalar variables can also contain arrays directly:
my = 1, 2, 3;say ; # OUTPUT: «[1 2 3]»say .^name; # OUTPUT: «Array»my = ;say ; # OUTPUT: «[1 2 3]»say .^name; # OUTPUT: «Array»
The big difference is that arrays inside a scalar act as one value in list context, whereas arrays will be happily iterated over.
my = 1, 2, 3;my = ;for # loop body executed 3 timesfor # loop body executed only oncemy = flat , ;say .elems; # OUTPUT: «6»my = flat , ;say .elems; # OUTPUT: «2»
You can force list context with @( ... )
or by calling the .list
method on an expression, and item context with $( ... )
or by calling the .item
method on an expression.
See the Perl 6: Sigils, Variables, and Containers article to learn more.
There are several reasons:
they make it easy to interpolate variables into strings
they form micro-namespaces for different variables and twigils, thus avoiding name clashes
they allow easy single/plural distinction
they work like natural languages that use mandatory noun markers, so our brains are built to handle it
they aren't mandatory, since you can declare sigilless names (if you don't mind the ambiguity)
You likely tried to mix string interpolation and key characters, like HTML tags:
my = "abc";say "$foo<html-tag>";
Raku thinks $foo
is a Hash and <html-tag>
is a string literal hash key. Use a closure to help it to understand you.
my = "abc";say "<html-tag>";
yield
?Raku has no yield
statement like Python does, but it does offer similar functionality through lazy lists. There are two popular ways to write routines that return lazy lists:
# first method, gather/takemy = gather while have_data()# second method, use .map or similar method# on a lazy listmy = (1..*).map(-> \x );
The say
statement in the following code sample
say A.new(x => 5).show-x;
does not print 5. Private attributes are private, which means invisible to the outside world. If the default constructor could initialize them, they would leak into the public API. Thus, in this particular code sample the attribute $!x
isn't initialized during object construction by the default constructor.
If you still want to initialize private attributes with the default constructor, you can add a submethod BUILD
to achieve such task:
say B.new(x => 5).show-x;
BUILD
is called by the default constructor (indirectly, see Object Construction for more details) with all the named arguments that the user passes to the constructor. :$!x
is a named parameter with name x
, and when called with a named argument of name x
, its value is bound to the attribute $!x
.
However, you shouldn't do that. If the attribute is declared as private, then it shouldn't be exposed to the environment outside the class (e.g., during object construction). On the other hand, if the attribute is public, there is no downside to declaring it that way with $.x
since the external view is read-only by default, and you can still access it internally with $!x
.
say
, put
and print
differ?The most obvious difference is that say
and put
append a newline at the end of the output, and print
does not.
But there's another difference: print
and put
convert their arguments to a string by calling the Str
method on each item passed to them while say
uses the gist
method. The gist
method, which you can also create for your own classes, is intended to create a Str
for human interpretation. So it is free to leave out information about the object deemed unimportant to understanding the essence of the object.
Or phrased differently, $obj.Str
gives a string representation, $obj.gist
provides a short summary of that object suitable for fast recognition by a human, and $obj.raku
gives a Raku-ish representation from which the object could be re-created.
For example, when the Str
method is invoked on a type object, also known as an "undefined value", the type is stringified to an empty string and a warn
ing is thrown. On the other hand, the gist
method returns the name of the type between parentheses (to indicate there's nothing in that value except the type).
my Date ; # $x now contains the Date type objectprint ; # empty string plus warningsay ; # OUTPUT: «(Date)»
If you'd like to show a debugging version of an object, it is probably better to use the rakudo-specific dd
routine. It essentially does a $obj.raku
and shows that on STDERR rather than STDOUT, so it won't interfere with any "normal" output of your program.
In short, say
is optimized for casual human interpretation, dd
is optimized for casual debugging output and print
and put
are more generally suitable for producing output.
put
is thus a hybrid of print
and say
; like print
, it calls the Str
method on the object. And like say
, it adds a newline at the end of the output.
token
and rule
?regex
, token
and rule
introduce regexes, but with slightly different semantics.
token
implies the :ratchet
or :r
modifier, which prevents the rule from backtracking.
rule
implies both the :ratchet
and :sigspace
(short :s
) modifier, which means a rule doesn't backtrace, and it treats whitespace in the text of the regex as <.ws>
calls (i.e., matches whitespace, which is optional except between two word characters). Whitespace at the start of the regex and at the start of each branch of an alternation is ignored.
regex
declares a plain regex without any implied modifiers.
die
and fail
?die
throws an exception.
fail
returns a Failure
object. (If the caller has declared use fatal;
in the calling lexical scope, fail
throws an exception instead of returning it.)
A Failure
is an "unthrown" or "lazy" exception. It's an object that contains the exception, and throws the exception if you try to use the Failure
as an ordinary object or ignore it in sink context.
A Failure
returns False
from a defined
check, and you can extract the exception with the exception
method.
Pointer
and OpaquePointer
?OpaquePointer
is deprecated and has been replaced with Pointer
.
Identifiers can include colon pairs, which become part of their name. According to Larry Wall's answer to the issue, We already had the colon pair mechanism available, so it was a no-brainer to use that to extend any name that needs to be able to quote uniquefying but non-standard characters (or other information with a unique stringification to such characters).
It depends on the operating system, windowing environment and/or editors. This page on entering Unicode characters specifies how it is done in the most popular operating systems and editors.
Currently the best developed is Rakudo (using multiple Virtual Machine backends). Historic implementations include Niecza (.NET) and Pugs (Haskell). Others are listed at Raku Compilers
A short answer is that Rakudo is written almost entirely in Raku. A more detailed answer is that Rakudo is written in a mixture of Raku and NQP ("Not Quite Perl"). NQP is a lightweight Raku-like environment for virtual machines; it's designed to be a high-level way to create compilers and libraries for virtual machines (such as MoarVM and JVM) using Raku syntax.
NQP is a mixture of (1) NQP code, (2) whatever language the underlying virtual machine is using, (3) some third-party C and Java libraries, and (4) some bootstrapping files created by earlier runs of the build process.
(not (not Nil))
Tools like App::InstallerMaker::WiX
allow you to create an installer that will package the compiler and your script. However, the currently available compilers do not support creating a standalone executable yet.
If you wish to help out, the Rakudo compiler on MoarVM backend has https://github.com/MoarVM/MoarVM/issues/875 issue opened as a place to discuss this problem.
A Rakudo Star release is typically produced quarterly, with release announcements posted on rakudo.org.
… As opposed to some other name that didn't imply all the things that the higher number might indicate on other languages.
The short answer is that it was Larry's choice under Rule 1.
The community considers Perl and Raku sister languages - they have a lot in common, address many of the same problem spaces, but Raku is not intended to replace Perl. In fact, both languages interoperate with each other.
Readiness of programming languages and their compilers is not a binary decision. As the language and the implementations evolve, they grow steadily more usable. Depending on your needs, Raku and its compilers may or may not be ready for you.
That said, version 6.c (Christmas 2015) is the first official release of Raku as a language, along with a validation suite and a compiler that passes it.
Raku unifies many great ideas that aren't usually found in other programming languages. While several other languages offer some of these features, none of them offer all of them.
Raku offers procedural, object-oriented AND functional programming methodologies.
Easy to use consistent syntax, using invariable sigils for data-structures.
Full grapheme based Unicode support, including Annex #29.
Clean, more readable regular expressions; taken to the next level of usability, with a lot more functionality. Named regular expressions improve ease of use.
Junctions allowing easy checking of multiple possibilities; e.g., $a == 1|3|42
(Is $a
equal to 1 or 3 or 42?).
Dynamic variables provide a lexically scoped alternative to global variables.
Emphasis on composability and lexical scoping to prevent “action at a distance”; e.g., imports are always lexically scoped.
Easy to understand consistent scoping rules and closures.
Powerful object orientation, with classes and roles (everything can be seen as an object). Inheritance. Subtyping. Code-reuse.
Introspection into objects and metaobjects (turtles all the way down).
MetaObject Protocol allowing for metaprogramming without needing to generate or parse code.
Subroutine and method signatures for easy unpacking of positional and named parameters.
Multi-dispatch for identically named subroutines/methods with different signatures, based on arity, types and optional additional code.
Compile time error reporting on unknown subroutines or impossible dispatch.
Optional gradual type-checking at no additional runtime cost. With optional type annotations.
Advanced error reporting based on introspection of the compiler/runtime state. This means more useful, more precise error messages.
Phasers (like BEGIN
/ END
) allow code to be executed at scope entry / exit, loop first / last / next and many more special contexts.
High level concurrency model, both for implicit as well as explicit multi-processing, which goes way beyond primitive threads and locks. Raku's concurrency offers a rich set of (composable) tools.
Multiple-core computers are getting used more and more, and with Raku these can be used thanks to parallelism, both implicit (e.g., with the >>
. method) and explicit ( start { code }
). This is important, because Moore's Law is ending.
Structured language support is provided to enable programming for asynchronous execution of code.
Supplies allow code to be executed when something happens (like a timer, or a signal, or a filesystem event).
react
/ whenever
/ supply
keywords allows easy construction of interactive, event driven applications.
Lazy evaluation when possible, eager evaluation when wanted or necessary. This means, for example, lazy lists, and even infinite lazy lists, like the Fibonacci sequence, or all prime numbers.
Native data types for faster, closer-to-the-metal, processing.
Interfacing to external libraries in C and C++ is fairly easy with Nativecall.
Interfacing with Perl (CPAN) and Python modules is fairly easy with Inline::Perl5 and Inline::Python
Can have multiple versions of a module installed and loaded simultaneously.
System administration simplified due to simpler update and upgrade policies.
Simple numeric computation without precision loss because of Rats (rational numbers).
Extensible grammars for parsing data or code (which Raku uses to parse itself).
Raku is a very mutable language (define your own functions, operators, traits and data-types, which modify the parser for you).
Large selection of data-types, plus the possibility to create your own types.
Multi-dimensional shaped or native arrays with proper bounds checking.
Execute code at any time during parsing of a grammar, or when a certain match occurred.
Adding a custom operator or adding a trait is as simple as writing a subroutine.
Automatic generation of hyper-operators on any operator (system or custom added).
Runs on a variety of back-ends. Currently MoarVM and JVM, JavaScript in development, more may follow.
Runtime optimization of hot code paths during execution (JIT).
Runs on small (e.g., Raspberry Pi) and large multi-processor hardware.
Garbage collection based: no timely destruction, so no reference-counting necessary. Use phasers for timely actions.
Methods can be mixed into any instantiated object at runtime; e.g., to allow adding out-of-band data.
Easy command-line interface accessible by MAIN
subroutine with multiple dispatch and automated usage message generation.
Fewer lines of code allow for more compact program creation. Huffman-coding of names allows for better readability.
Lazy lists defined with a simple iterator interface, which any class can supply by minimally supplying a single method.
Ability to use hyphens and other non-alphanumeric ASCII characters as well as certain Unicode characters in identifiers. (Using hyphens instead of underscores in test is commonly called "kebab case" among its users. See also "camel case" and "snake case": https://en.wikipedia.org/wiki/Letter_case#Special_case_styles.)
Raku's mottos remain the same as they have been for Perl all along: “Perl is different. In a nutshell, Perl is designed to make the easy jobs easy, without making the hard jobs impossible.” and “There Is More Than One Way To Do It”. Now with even more -Ofun added.
That depends on what you are doing. Rakudo has been developed with the philosophy of "make it work right then make it work fast." It's fast for some things already but needs work for others. Since Raku provides lots of clues to the JIT that other dynamic languages don't, we think we'll have a lot of headroom for performance improvements.
The following crude benchmarks, with all the usual caveats about such things, show that Raku can be faster than Perl for similar tasks if the big weaponry is included, that is, if Raku features are used to its full extent; at the same time, Perl can be faster if only the bare bones are included. Similar situations can be observed when comparing Raku to other languages.
Try it on your system. You may be pleasantly surprised!
Examples:
# Raku version;for 1..1_000_000 ->
# Perl version;use Moose;has i => (is => 'rw');__PACKAGE__->meta->make_immutable;for my (1..1_000_000)1;# Another Perl version that offers bare-bones set of features# compared to Moose/Raku's version but those are not needed in this# specific, simple program anyway.;use Mojo::Base -base;has 'i';for my (1..1_000_000)1;
You might want to use this program for comparing performance, too. It works under both languages, as long as perl -Mbigint
is used for invocation for Perl.
my (, ) = (1, 0);for (0..100_000)print ;