2021-12-09 13:16:47 +00:00
|
|
|
# Raku rocks
|
|
|
|
|
|
|
|
Raku (formerly Perl 6) is a programming language which, despite its
|
|
|
|
former name, it's a very different language from perl. Altough if you
|
|
|
|
already know Perl, learning Raku will be relatively easy.
|
|
|
|
|
|
|
|
Raku introduces (or makes usable) concepts that perl didn't have (or
|
|
|
|
had but were useless and discouraged) in Perl such as Threads,
|
|
|
|
promises, lazy evaluation, and grammars.
|
|
|
|
|
|
|
|
Sigils in Raku make sense unlike in Perl, for example:
|
|
|
|
|
|
|
|
~~~
|
|
|
|
# Perl:
|
|
|
|
my %hash = (key1 => "value", key2 => "value2");
|
|
|
|
$hash{key1} # value;
|
|
|
|
# Raku:
|
|
|
|
my %hash = (key1 => "value", key2 => "value2");
|
|
|
|
%hash{"key1"} # Value
|
|
|
|
~~~
|
|
|
|
|
|
|
|
If a hash is a hash, it is a hash, it won't be converted to a scalar
|
|
|
|
when you want to retrieve data from that hash. Unlike in Perl.
|
|
|
|
|
|
|
|
Raku, unlike perl is a typed programming language, by default all
|
|
|
|
variables you declare are of the type "Any", which means that variable
|
|
|
|
can have any time and can be converted to other type. Nevertheless you
|
|
|
|
can specify which type you want the variable to be:
|
|
|
|
|
|
|
|
~~~
|
|
|
|
my Int $n = 3;
|
|
|
|
my Str $s = "hello world";
|
|
|
|
~~~
|
|
|
|
|
|
|
|
There is a type hierarchy, which means types are based on other
|
|
|
|
types. All types are based on the type `Mu`[fn:1].
|
|
|
|
|
|
|
|
For example, the type `atomicint`, and `bool` derives from the type
|
|
|
|
`Int` which derives from `Cool` which derives from `Any` which derives
|
|
|
|
from `Mu`. All roads lead to Rome and all types lead to `Mu`.
|
|
|
|
|
|
|
|
Raku also has a decent Object Oriented interface:
|
|
|
|
|
|
|
|
~~~
|
|
|
|
Class Socket {
|
|
|
|
has Int $.sockfd;
|
|
|
|
|
|
|
|
method new ($path) {
|
|
|
|
my $mfd = create_socket();
|
|
|
|
connect_socket($mfd,$path);
|
|
|
|
self.bless(sockfd => $mfd);
|
|
|
|
}
|
|
|
|
method send($str) {
|
|
|
|
my $len = $str.chars;
|
|
|
|
write_to_sock(self.sockfd, $str, $len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
my $sock = Socket.new("path/to/socket");
|
|
|
|
$sock.write("hello from raku!");
|
|
|
|
~~~
|
|
|
|
|
|
|
|
Calling C functions from Raku is stupidly easy, to do this only use
|
|
|
|
the [NativeCall](https://docs.raku.org/language/nativecall) module
|
|
|
|
which is included in the standard library, consider the following:
|
|
|
|
|
|
|
|
file.c:
|
|
|
|
~~~
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
int
|
|
|
|
print_string(const char *s)
|
|
|
|
{
|
|
|
|
puts(s);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
|
|
|
You have to compile it so it's a shared library:
|
|
|
|
|
|
|
|
`gcc -fpic -shared file.c -o libfile.so`
|
|
|
|
|
|
|
|
file.raku:
|
|
|
|
~~~
|
|
|
|
use NativeCall;
|
|
|
|
|
|
|
|
# Libpath, raku will add the lib and the .so automatically so you don't
|
|
|
|
# have to put libfile.so
|
|
|
|
|
|
|
|
constant LIBPATH = "$*CWD/file";
|
|
|
|
|
|
|
|
# Takes a Str as argument and returns and int32 (which is just an alias to Int)
|
|
|
|
sub print_string(Str --> int32) is native(LIBPATH) { * }
|
|
|
|
|
|
|
|
print_string("C function running in raku");
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
|
|
|
It will output:
|
|
|
|
|
|
|
|
`C function running in raku`
|
|
|
|
|
|
|
|
Which was expected. Obviously you can import syscalls and any kind of
|
|
|
|
functions you can run in C. Which is useful for doing stuff that is
|
|
|
|
not in the Raku standard library but it's in the C stdlib, such as
|
|
|
|
creating sockets which all the flags you want, or calling `fork()`
|
|
|
|
(which is discouraged as you can use threads and async functions
|
|
|
|
really easily, but if you *really* want to call `fork()` you can call
|
|
|
|
`fork()`.
|
|
|
|
|
|
|
|
## Concurrency in Raku
|
|
|
|
|
|
|
|
Async functions in raku are something very easy. The [language
|
|
|
|
website](https://raku.org) give us this example:
|
|
|
|
|
|
|
|
~~~
|
|
|
|
start { sleep 1.5; print "hi" }
|
|
|
|
await Supply.from-list(<A B C D E F>).throttle: 2, {
|
|
|
|
sleep 0.5;
|
|
|
|
.print
|
|
|
|
}
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
2021-12-09 13:19:13 +00:00
|
|
|
|
|
|
|
Output is "ABCDhiEF"
|
|
|
|
|
2021-12-09 13:16:47 +00:00
|
|
|
the `start` block is called asyncronously, so it sleeps 1.5 seconds
|
|
|
|
and then prints "hi" while the other part prints 2 letters every 0.5
|
|
|
|
seconds. so after printing ABCD, 1.5 seconds have passed, so it will
|
|
|
|
print the "hi" form the `start {}` block.
|
|
|
|
|
|
|
|
Raku also has promises:
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
|
|
|
sub counter(Int $n) {
|
|
|
|
for 0..$n -> $i {
|
|
|
|
if $i == 21474834 {
|
|
|
|
return "There";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
my $promise = start {
|
|
|
|
counter(21474834);
|
|
|
|
};
|
|
|
|
|
|
|
|
$promise.then({say .result}); # Will print "There" after finishing.
|
|
|
|
|
|
|
|
say "I'm doing other stuff";
|
|
|
|
say "Blah, blah";
|
|
|
|
sleep(1000); # Simulate stuff-doing
|
|
|
|
~~~
|
|
|
|
|
|
|
|
the `.then` method takes as parameter a block of code, which will be
|
|
|
|
executed after finishing the process. In that code I use `sleep(1000)`
|
|
|
|
to simulate stuff-doing, but if you finished all the stuff you have to
|
|
|
|
do and need the promise to finish, you only do
|
|
|
|
`$promise.result`. Which will wait until it finishes. This is like
|
|
|
|
joining a thread.
|
|
|
|
|
|
|
|
## Rakudo
|
|
|
|
|
|
|
|
Rakudo is the main implementation of the Raku programming language. It
|
|
|
|
compiles Raku code to be run in MoarVM or, if wanted, the JVM[fn:2].
|
|
|
|
|
|
|
|
[fn:1]: Haha discordian reference!
|
|
|
|
[fn:2]: MoarVM is the most used because it's the fastest raku implementation. But you can compile Rakudo to use the JVM if you really want to.
|