Day 5 – How to use the docs

…or why (nearly) everything is an object.

Spread out over all the pages of the official documentation of Perl 6, the class Signature is linked to more then 40 times. That shows not only that signatures are everywhere but also demonstrates a peculiarity of Perl 6 that will become more important as the language matures. No really, we are not done yet.

But first let’s have a look at some code.

multi sub trait_mod:<is> (Sub $s, :$foo!) is foo {
    say 'is foo called'
}
sub bar {}
&trait_mod:(&bar, :foo);

Here we define a trait that happens to be of type Sub which Rakudo (re)defines in Sub.pm. So there is actually a class for this build-in type. In fact, there are classes for anything besides classes and grammars. Having a Class for class would be a bit circular and prevent a slang to define its own object system. That you can do with Metamodel::ClassHOW, which is the Class behind class. But back to the trait.

A trait is somewhat macroish in nature as it is applied at compile time to some object its signature refers to. That allows the MMD to pick the candidate defined above when we use it with is foo. (There are a whopping 91 candidates of is defined in Rakudo.) Since it’s called at compile time it has to be called with something that exists at that time. All those classes for Sub, Label and friends provide a nice target for such a call. And yes, you can apply a trait to a label if you call it the right way in a BEGIN phaser. Combined with the power of compile time mixins and the the mighty .wrap you can go wild and improve the tool that is most dear to you — the Perl 6 compiler. If you observed the example carefully you likely spotted that the trait is applied to itself. If you really want to you could have infinite recursion at compile time.

Perl 6 is a dynamic dynamic language. The programs you write are dynamic and you can mend them and bend them to your will, both at compile- and runtime. And so you can do with the compiler. And that leads us to how to use the docs. Since language features are represented as a class, we link heavily to those classes to provide detailed discussions and you are encouraged to follow those links before you continue with the main paragraph the link refers from.

Macros will make good use of all those objects. With any luck next year will show us how.

Day 13 – A new trait for old methods

use v6;

El_Che expressed the desire on IRC to have Perl 6 watch his fingers when typing named arguments. It is indeed quite easy to send a wrong name the right way. Luckily we can help him.

First we need some exception to throw. Perl 6 kindly creates a constructor for us that deals with filling all attributes with values, so we can provide details when we throw the exception.

class X::Parameter::ExtraNamed is Exception {
    has $.extra-parameters;
    has $.classname;
    has $.method-name;
    method message () {
        "The method $.method-name of $.classname is offended by the named parameter(s): $.extra-parameters";
    }
}

We want to modify a method (.new in this case) so we need a trait. A trait is a modification of the Perl 6 grammar and a subroutine. It’s name comes from the required named argument. The thing it operates on is stored in the first positional. In our case that’s a method.

multi sub trait_mod:<is>(Method $m, :$strict!){

We want to check named arguments against the list of arguments that are defined in the methods signature. We have to store them somewhere.

    my @named-params;

When we provide some error message we may want to name the class the method is member of.

    my $invocant-type;
    my $method-name = $m.name;

The signature of a method can provide us with a list of parameters.

    for $m.signature.params -> $p {

But first the classname.

        $invocant-type = $p.type if $p.invocant;

We are only interested in named arguments.

        next unless $p.named;

Each named argument starts with a sigil ($ in this case). That would get in our way, so we strip it from the method name and store the rest for safekeeping.

        @named-params.push: $p.name.substr(1);
    }

After we got all the information we need, we come to the business end of our trait. We wrap the method in a new method. We only want to peek into it’s argument list so we take a capture. Conveniently a capture provided us with a method to get a list of all named arguments it contains.

    $m.wrap: method (|args) {

We first check with the subset operator (<=) if there are any named arguments we don’t like and if so, we use the set difference operator (-) to name only those. The exception we defined earlier takes care of the rest.

        X::Parameter::ExtraNamed.new(
            method-name => $method-name,
            classname => $invocant-type.perl, 
            extra-parameters => args.hash.keys (-) @named-params
        ).throw unless args.hash.keys (<=) @named-params;

If all named arguments are fine, we can call the wrapped method and forward all arguments kept in the capture.

        callwith(self, |args);
    }
}

Let’s test it.

class Foo {
    has $.valid;

Perl 6 will deal with the positional part, our trait is strict will learn about :$valid.

    method new (Int $p1, :$valid) is strict { self.bless(valid => $valid) }
    method say () { say 'Foo' }
}

New instance is new and got 2 extra named arguments the method doesn’t know of.

Foo.new(42, valid => True, :invalid, :also-invalid).say;

OUTPUT:

<<The method new of Foo is offended by the named parameter(s): invalid also-invalid>>

Traits are a nice way to generalise behaviour of methods and subroutines. Combined with exceptionally good introspection Perl 6 can be mended and bended to fit into any Christmas package. Merry 1.0 and a happy new Perl 6 to you all!

Day 2 – 2 bind or !2 bind

Is a question one may want to answer while programming in Perl 6. Let me explain with the help of a Proxy and a script.

11 sub BOS() {
12 	my Str $c-value; # closure variable
13 	return Proxy.new(
14 		FETCH => method () { $c-value },
15 		STORE => method ($new-value) { 
16 			die $?LINE ~ ' Semper invicta!' if $new-value.tc ~~ any <Supermutant Ghoul Synth>; 
17 			$c-value = $new-value;
18 		}
19 	);
20 }
21 
22 # Let's prefix &say with the line number it's called from
23 my sub say(**@args is raw) { 
24 	print callframe(1).line; 
25 	print ' ' ~ .Str ~ $*OUT.nl-out for @args
26 }
27 
28 my Str $who-container = BOS;
29 my Str \who-raw = BOS;
30 my Str $who-bound := BOS;

Now we have three variables, of which one is a buildin container. All of them refer to a ‘magic’ variable. Via the methods given to Proxy.new, we can control what values are allowed to be stored. As you likely have guessed already, our magic variable doesn’t like Supermutants and other unhumanly creatures. There is a catch. The container that is still a container wont do what we expect.

43 $who-container = 'supermutant';
44 say $who-container;
45 
46 try {
47 
48 	who-raw = 'ghoul';
49 	say who-raw;
50 
51 	CATCH {
52 		when X::AdHoc { warn $_.Str }; # line 52
53 	}
54 }
55 
56 who-raw = 'Cait';
57 say who-raw;
58 
59 try {
60 
61 	$who-bound = 'synth';
62 	say $who-bound;
63 
64 	CATCH {
65 		when X::AdHoc { warn $_.Str }; # line 65
66 	}
67 }
68 
69 $who-bound = 'Dogmeat';
70 say $who-bound;

By handling X::AdHoc we can turn a fatal die into a harmless warn. For $who-container we don’t need to do that. Let’s see how they differ.

79 say $who-container.VAR.^name; # Scalar
80 say who-raw.VAR.^name; # Proxy
81 say $who-bound.VAR.^name; # Proxy

With VAR we get access to the typeobject of the container we introduce with my or our. Binding allows us to set the type of the container, what is not the same thing as the type of the value stored in the container. Let’s have a look at the type checks.

92 say so BOS() ~~ Proxy; # False
93 say so BOS() ~~ Str; # True
94 
95 say so BOS().VAR ~~ Proxy; # True
96 say so BOS().VAR ~~ Str; # False

The type of the returned value is the type of $c-value. The container type is Proxy. We can use that to decide at runtime if we need to bind.

105 my Str $foo;
106 $foo = BOS if BOS().VAR ~~ Scalar;
107 $foo := BOS if BOS().VAR ~~ Proxy;
108 say $foo.VAR.^name; # Proxy

There is no way for a function to force binding on its returned value. So we have to be careful with returned values. Luckily Perl 6 provides us with enough introspection so we can handle it at runtime.

A bound Proxy can help us to probe Rakudo a little.

120 my $c-zeta;
121 my $counter;
122 my $zeta := Proxy.new(FETCH => { $counter++; $c-zeta }, STORE => -> $, $new { $c-zeta = $new } );
123 
124 $zeta = 'how often will it be fetched?';
125 say $zeta;
126 say $counter; # 5

On Rakudo Beta 1 FETCH is called 5 times just to .say the value. Let’s see how far our probe will reach.

135 f($zeta, $zeta, $zeta);
136 
137 sub f($c, $c-rw is rw, \r){
138 	say $c.VAR.^name; # Scalar
139 	say $c-rw.VAR.^name; # Proxy
140 	say r.VAR.^name; # Proxy
141 }

The default for sub and method parameters is ro, what does what is said on the tin. Both is rw and a sigilless parameter are using binding.

150 constant lover = BOS();
151 
152 say lover.VAR.^name; # Proxy
153 
154 lover = 'Piper';
155 say lover; # Piper

If we declare a constant Perl 6 will also force a binding. Allowing sigillessness may give it away. Proxy isn’t all that constant though. So we can turn a constant value into a variable. You just can’t trust those dynamic languages.

166 constant fibonacci = 0, 1, *+* ... *;
167 
168 say fibonacci[^10]; # (0 1 1 2 3 5 8 13 21 34)
169 say fibonacci.VAR.^name; # Seq

But then a sequence isn’t really constant. It’s values are calculated at runtime, for as many values we ask for.

178 try {
179 	fibonacci[11] = 0;
180 	CATCH { when X::Assignment::RO { say .Str } }
181 }

If we want to take advantage of type checks, we have to make sure a call to FETCH does return a default value of the right type. That’s easy to do with a type capture. If we omit the type in STORE we can still cheat to our heart’s content. If we don’t want to cheat, we could use ::T in STORE‘s signature.

193 sub typed(::T $type = Any){ # you may not want to default to Any, here we do
194 	my T $c-typed-value;
195 	my $c-typed-value-type-string = $c-typed-value.WHAT.perl;
196 	return Proxy.new(
197 		FETCH => method () { $c-typed-value },
198 		STORE => method ($new-value) { 
199 			$c-typed-value = $new-value ~~ Str 
200 				?? ( $new-value.comb>>.ord.sum / $new-value.chars )."$c-typed-value-type-string"()
201 				!! $new-value;
202 		}
203 	);
204 }
205 
206 my Int $typed-container := typed(Int);
207 say $typed-container = 11;
208 $typed-container = 'FOO';
209 say $typed-container;

If we do fancy container magic, we have to implement readonlyness by hand.

217 my $constant-variable := Proxy.new( 
218 	FETCH => { q{Merry 1.0!} }, 
219 	STORE => -> $, $ { die X::Assignment::RO.new(typename => 'none really') } # line 219 
220 );
221 
222 say $constant-variable;
223 
224 $constant-variable = 'The Grudge stole Christmas!'; # this will die in line 219 
225 say $constant-variable;

Binding is a powerful tool to expose the dynamic nature of Perl 6 and allows us to take advantage of that nature. No matter if you bind or not I wish you a Merry 1.0 and a happy new year!