kill9/rocks/computers/software/langs/raku.md

5.6 KiB

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 Mu1.

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(); # This is a function written in C called with NativeCall
          connect_socket($mfd,$path); # Idem
          self.bless(sockfd => $mfd); # Give the attributes to the object
     }
    	method send($str) {
		my $len = $str.chars;
		write_to_sock(self.sockfd, $str, $len); # C func
	}
}

my $sock = Socket.new("path/to/socket");
$sock.send("hello from raku!");

Calling C functions from Raku is stupidly easy, to do this only use the NativeCall module which is included in the standard library, consider the following:

file.c:

#include 

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 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
}

Output is "ABCDhiEF"

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 JVM2.

Resources

The language documentation site is pretty solid for reference. But if you want to learn the language from scratch you can use https://raku.guide. If you already know a programming language you can take the tour which shows you how to do things you already know in raku:

There are channels in libera chat to discuss raku, #raku (general talk about the language), #raku-beginner (for beginner questions) and #raku-dev (for Rakudo devel)


  1. Haha discordian reference! ↩︎

  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. ↩︎