Archive
Nil statement considered harmful
Nil is the little parent of Failure and represents the absence of a value. It’s the John Doe of the Perl 6 world. Its undefined nature means we can talk about it but we don’t know its value. If we try to coerce it to a presentable value we will be warned.
my $a := Nil; dd $a.Str, $a.Int; # OUTPUT«Use of Nil in string context in block <unit> at <tmp> line 1Use of Nil in numeric context in block <unit> at <tmp> line 1""0»
As the output shows it still coerces to the closest thing we have for a undefined string or number. Some times the empty string is outright dangerous.
sub somesub { Nil }; my $basename = somesub; spurt("$basename.html", "<body>oi!</body>");
If we do that in a loop we would drop plenty of “.html” into the filesystem. Since this can depend on input data, some cunning individual might take advantage of our neglect. We can’t test for Nil
in $basename
, because assignment of Nil reverts the container to it’s default value. The default default value for the default type is Any
. We can protect ourselves against undefined values with a :D
-typesmile.
my Str:D $basename = somesub;
That would produce a runtime error for anything but Nil
, because the default value for a container of type Str:D
is Str:D
. A type object that happens to be undefined and wont turn into anything then the empty string. Not healthy when use with filenames.
We still get the warning though, what means that warn is called. As it happens warn
will raise a control exception, in this instance of type CX::Warn
. We can catch that with a CONTROL block and forward it to die
.
sub niler {Nil}; my Str $a = niler(); say("$a.html", "sometext"); say "alive"; # this line is dead code CONTROL { .die };
That’s quite a good solution to handle interpolation problems stemming from undefined values. Given that any module or native function could produce undefined values makes it hard to reason about our programs. Having the control exception allows us to catch such problems anywhere in the current routine and allows us to deal with more then one place where we interpolate in one go.
Sometimes we want to stop those values early because between an assignment of a undefined value and the output of results minutes or even hours can pass by. Fail loudly and fail early they rightfully say. Type smileys can help us there but for Nil it left me with a nagging feeling. So I nagged and requested judgment, skids kindly provide a patch and judgement was spoken.
Perl 6 will be safe and sound again.
Sneaky methods
As one would expect methods can be declared and defined inside a class definition. Not so expected and even less documented are free floating methods declared with my method
. Now why would you want:
my method foo(SomeClass:D:){self}
The obvious answer is the Meta Object Protocols add_method-method, as can be found in Rakudo:
src/core/Bool.pm 32: Bool.^add_method('pred', my method pred() { Bool::False }); 33: Bool.^add_method('succ', my method succ() { Bool::True }); 35: Bool.^add_method('enums', my method enums() { self.^enum_values });
There is another, more sneaky use for such a method. You may want to have a look at what is going on in a chain of method calls. We could rip the expression apart and insert a one shot variable, do our debugging output, and continue in the chain. Good names are important and wasting them on one shot variables is unnecessary cognitive load.
<a b c>.&(my method ::(List:D){dd self; self}).say; # OUTPUT«("a", "b", "c")(a b c)»
We can’t have no name without an explicit invocant, because Perl 6 wont let us, so we use the empty scope ::
to make the parser happy. With a proper invocant, we would not need that. Also, the anonymous method is not a member of List. We need to use postfix .& to call it. If we need that method more then once we could pull it out and give it a name.
my multi method debug(List:D:){dd self; self}; <a b c>.&debug.say; # OUTPUT«("a", "b", "c")(a b c)»
Or we assign it as a default argument if we want to allow callbacks.
sub f(@l, :&debug = my method (List:D:){self}) { @l.&debug.say }; f <a b c>, debug => my method ::(List:D){dd self; self}; # OUTPUT«("a", "b", "c")(a b c)»
In Perl 6 pretty much everything is a class, including methods. If it’s a class it can be an object and we can sneak those in wherever we like.
It’s blocks all the way down
While playing with Perl 6 on glot.io I learned that they really like docker with the simple program:
dir('/')>>.Str.say;
And I wondered if there is a nice idiom for recursing into directories. IO::Path.dir
will return a Seq
of IO::Path
objects. That’s why the >>
. hyperoperator works. It wont recurse of cause as there is no sub to recurse with. After some open eye meditation I found what I was looking for quite some time.
A block in Perl 6 is a Callable with one positional argument. That argument is bound to the topic $_
. That’s why we can do:
for 1,2,3 { .say }
Recursing into a directory would be easy if we turn the Str
'/'
into a IO::Path
object and check if we got a directory and call the block with that element. That block would need a name, what we could do with my &block = { Nil }
, or we use the compile time variable &?BLOCK
.
for '.' { .Str.say when !.IO.d; .IO.dir()>>.&?BLOCK when .IO.d }
The form .&?BLOCK
will treat the call like a method call, what means the object left of .
will be the first parameter of the call, where the invocant belongs.
I believe this is a fairly nice example how to use &?BLOCK
to get rid of nested loops and one shot variables. It will be added shortly to the docs.
With the kind help of Zoffix the example was golfed down further.
{ .d && .dir».&?BLOCK || .put }(".".IO)
Perl 6 can recurse with the best of them. :)
Disecting subsets
While fighting with htmlily.p6 I found myself in need of a tool that shows me the structure of a pod6 file. Since all nodes are subclasses of Pod::Block and it’s tree structure is walked through simply by recursively descending into .contents, it was easily done. Just recurse and print .^name with some indentation. Putting a stack on walks back is needed because Pod::Block doesn’t provide a .parent method. A bit ugly but not really a problem.
What did confuse me was the fact that .^name on subsets that provide Pod::FormattingCode with a better name didn’t carry a proper type name. And in fact, a subset does inject a new name into the scope but does not change the type of an object that passed a type check against it.
subset FooStr of Str; my FooStr $s; sub f(FooStr $s){ say $s.^name }; f("abc"); # OUTPUT«Str»
That is fine if you want to use a subset as a type check. Since it passed the check, it must be of that type or a type that behaves in the same way.
I wanted to do introspection, what means turning a type object into a name. Even worse I wanted to turn a type object into a name of a type that is narrower. Since there is no reference from a type to all its sub types, Perl 6 could not help me there. At least not directly.
Luckily I put the subsets into a inline package. When you stick Foo::Bar::
in front of a name, Perl 6 will kindly generate a package for you and put the new types inside. Since a package is a Stash with a funky name, we can iterate over it’s key-value-Pairs. The keys are names and the values are type objects.
Pod::FormattingCode::.pairs.first({ $node ~~ $^a.value }).key
In my case there is a 1:1 relationship between a subset and it’s base type properties, so I can be sure that the first match is correct.
A nice example how using common data structures in the language implementation and exposing them to the programmer, can help Perl 6 to help you.
I don’t need conditionals either
While reading John A De Goes’ blog post about how to rid functions of variables tied to conditions, I wondered how I would do that in Perl 6.
The objective of his first example is to compare two strings case insensitive. Easy!
say "abc".fc eq "Abc".fc;
And then my mind started to wander off. I took a mental note and finished reading about ridding of ifs. Returning to my mental note I concluded: “There must be a nicer way to write that!”. It’s Perl 6 after all.
How about the function combinator?
my &ieq = &infix:<eq> ∘ &fc;
That didn’t work because ∘
cares about the number of arguments of its first operand but doesn’t about its second. What I actually need would be a loop over the two strings calling .fc
on each of them.
my @l = <abc Abc>>>.fc;
So I tried to fix the function combinator resulting in a gist. It’s now special cased for the 2nd operand to have just one argument. I felt a bit uneasy about that solution. Maybe because it would require a PR to Rakudo.
And then I realised that I might just bind a pointy to a operator name. I didn’t doc that so I checked and we indeed missed that spot. Short test via camelia.
my &infix:<foo> := -> {}
That worked. So let’s have a case insensitive string compare infix operator.
my &infix:<ieq> = -> |l { [eq] l>>.fc }; say "abc" ieq "Abc"; # OUTPUT«True»
Nice, short and no conditionals that could confuse John.
2 + 2 = 3
No really, when building a custom tenary operator I found that when combining two infix operators that both take 2 arguments I could emulate a tenary operator that takes 3 arguments.
But let’s start with the beginning. While looking at Pod::To::BigPage I was wondering if I ask for the right thing.
($node.caption ?? '<caption>' ~ $node.caption.&handle() ~ '</caption>' !! '' )
Do I really want to check for trueness or would defindness be more appropriate? It would be easy to fix.
($node.caption.defined ?? '<caption>' ~ $node.caption.&handle() ~ '</caption>' !! '' )
Problem solved. Well, somehow it doesn’t feel right to require a method call given that we got control structures with with/without
and operators like //
that check for defindness. Also there is no guarantee that a true thing is also defined.
say [0.Bool, 0.defined]; # putting arguments of say into [] # OUTPUT«[False True]» # will put a whitespace between elements
Also, undefined things can be true.
my $v = Any but True; say [$v.Bool, $v.defined]; # OUTPUT«[True False]»
So why not define a tenary operator that tests for definedness? Because Rakudo wont let us just yet. Defining two infix operators that are chained is quite easy though.
sub infix:<?//>(\a, \b -->DefinedAlternationContainer) { ??? } sub infix:<!!>(DefinedAlternationContainer:D \cont, \b) { ??? }
We have to make sure that we don’t collide with any other module that provides such an operator (we would need a multi sub). This can be done with an intermediary type that binds the two together.
class DefinedAlternationContainer { has $.item; has $.condition-was-defined; }
It holds the second argument and the result of the condition from the first infix. Which is used by the 2nd infix to decided if third tenary operand or the the 2nd is returned. So we can write:
my $falsish = 2 but False; say $falsish ?// <defined> !! <undefined>; # OUTPUT«defined»
For your convenience I took the liberty write a module, put it into the ecosystem and on github.