Archive

Archive for the ‘Uncategorized’ Category

Leaving out considered dangerous

January 7, 2017 1 comment

A knowledge seeker asked us why a loop spec allows $i>10 but not $i<10. The reason is that the postcircumfix:«< >» changes the grammar in such a way that it expects a list quote after the $i. As a result you get the following.

loop (my $i=0;$i<10;$i++) {};
# OUTPUT«===SORRY!=== Error while compiling ␤Whitespace required before < operator␤at :1␤------> loop (my $i=0;$i<10;$i++) {};⏏␤    expecting any of:␤        postfix␤»

I tried to illustrate the problem by making the $i>10 case fail as well by defining a new operator.

sub postcircumfix:«> <»($a){}; loop (my $i=0;$i>10;$i++) {};
# OUTPUT«===SORRY!=== Error while compiling ␤Unable to parse expression in postcircumfix:sym«> <»; couldn't find final $stopper ␤at :1␤------> rcumfix:«> <»($a){}; loop (my $i=0;$i>10⏏;$i++) {};␤    expecting any of:␤        s…»

I concluded with the wisdom that that Perl 6 is a dynamic dynamic language. While filing a related bug report I made the new years resolution to put a white space around each and every operator. You may want to do the same.

Categories: Perl6, Uncategorized

Perl 6 is Smalltalk

January 4, 2017 1 comment

Masak kindly pointed the general public to a blog post that talks about how awesome Smalltalk is.
The example presented there reads:

a < b
  ifTrue: [^'a is less than b']
  ifFalse: [^'a is greater than or equal to b']

The basic idea is that ifTrue and ifFalse are methods on the class Bool. Perl 6 don’t got that and I thought it would be tricky to add because augment enum doesn’t work. After some tinkering I found that augment doesn’t really care what you hand it as long as it is a class. As it happens Rakudo doesn’t check if the class is really a class, it simply looks for a type object with the provided name. The following just works.

use MONKEY-TYPING;
augment class Bool {
    method ifTrue(&c){ self ?? c(self) !! Nil; self }
    method ifFalse(&c){ self ?? Nil !! c(self); self }
}

(1 < 2)
    .ifTrue({say ‚It's True!‘})
    .ifFalse({ say ‚It's False!‘});

If we call only one of the new methods on Bool, we could even use the colon form.

(True)
    .ifTrue: { say "It's $^a!" };

As you likely spotted I went a little further as Smalltalk by having the added methods call the blocks with the Bool in question. Since Block got a single optional positional parameter the compiler wont complain if we just hand over a block. If a pointy block or a Routine is provided it would need a Signature with a single positional or a slurpy.

Please note that augment on an enum that we call a class is not in the spec yet. A bug report was filed and judgement is pending. If that fails there is always the option to sneak the methods into the type object behind Bool at runtime via the MOP.

And so I found that Perl 6 is quite big but still nice to talk about.

UPDATE: There where complains that IfTrue contained an if statement. That’s was silly and fixed.

Categories: Perl6, Uncategorized

Awesome and Custom

December 25, 2016 1 comment

While toying with roles to find a better example for our class tutorial I believe to have stumbled onto a nice idiom. And so I wrote:

role Unitish[$unit = fail('Please provide a SI unit quantifier as a Parameter to the role Unitish')]

What leads to the following error message when the role argument is missing.

Could not instantiate role 'Unitish':
Please provide a SI unit quantifier as a Parameter to the role Unitish
  in any  at gen/moar/Metamodel.nqp line 2441
  in any protect at gen/moar/stage2/NQPCORE.setting line 802
  in any specialize at gen/moar/Metamodel.nqp line 2428
  in any specialize at gen/moar/Metamodel.nqp line 2644
  in any compose at gen/moar/Metamodel.nqp line 3010
  in any generate_mixin at gen/moar/Metamodel.nqp line 1319
  in any  at gen/moar/Metamodel.nqp line 1235
  in any mixin at gen/moar/Metamodel.nqp line 1270
  in sub postfix:<s> at si.p6 line 12
  in block <unit> at si.p6 line 14

So instead of letting the compiler say: “Dude, the module author wants you to provide a Str!”, I can actually tell the user what the string should look like. The way I’m using it results in a runtime error. The does-operator can be executed at compile time, providing awesome error messages the way you want.

Categories: Uncategorized

These keys are LTA

September 25, 2016 1 comment

While toying around with enums as boolean options to a routine, i found the default error message less then awesome.

Constraint type check failed for parameter '@options'

It would be hard to be even less specific. Let’s create a few exceptions to tell what is going on when things go wrong.

class X::Paramenter::Exclusive is Exception {
has $.type;
    method message {
        "Parameters of {$.type.perl} are mutual exclusive"
    }
}

Now we can check if options of Find::Type are exclusive and complain accordingly.

&& ( exclusive-argument(@options, Find::Type) or fail X::Paramenter::Exclusive.new(type => Find::Type) )

class X::Parameter::UnrecognisedOption is Exception {
    has $.type;
    has $.unrecognised;
    method message {
        "Option { $.unrecognised } not any of { $.type.map({ (.^name ~ '::') xx * Z~ .enums.keys.flat }).flat.join(', ') }"
    }
}

Since enums are containers for types and those got names we can use set operators to check and single out none matching options (basically anything the +@options slurps up we don’t know).

or fail X::Parameter::UnrecognisedOption.new(type => (Find::Type, Find::Options),
    unrecognised => .item ∖ (|Find::Type::.values, |Find::Options::.values) )

Stitching the error message together is a bit more involved because we can get a list of all enum keys in a given enum but those don’t know their qualified name. We have to prefix with the enum name and :: by hand.

class X::Parameter::UnrecognisedOption is Exception {
    has $.type;
    has $.unrecognised;
    method message {
        "Option { $.unrecognised } not any of { $.type.map: { (.^name ~ '::') xx * Z~ .enums.keys.flat } }"
    }
}

This results in a much more awesome error message:

Option 42 not any of Type::File, Type::Dir, Type::Symlink, Options::Recursive, Options::Keep-going

This looks all quite regular. We have a slurpy that is kind of parameterised with one or many enums and those enums may have a flag telling if they act like radio buttons. Sounds like this idiom would fit nicely into a module.

Categories: Uncategorized

Keys are optional

September 22, 2016 1 comment

On my quest to a concurrent File::Find I found the need to have arguments (in this case as Bool) that are of a group of sorts and are mutual exclusive. Enums are very groupy, introduce easy to use names into the scope (directly or via is export) and should be easy to make mutual exclusive. The easy part was a bit naive because typed slurpy arguments are not supported (yet). If there is no easy way, there must be a hard way that is possible.

First let’s define two enums that serve as options to find.

package Find {
  enum Type (<File Dir Symlink>);
  enum Options (<Recursive Keep-going>);
}

Now we can have a where-clause that first checks if all members of a slurpy array are either of type Find::Type or Find::Options. Then we can check how many elements of Find::Options there are. Since there can be only one we complain about exclusiveness if there are to many.

+@options where {
  @options.all (elem) (Find::Type::.values (|) Find::Options::.values)
  && (+(@options.grep: * ~~ Find::Type) <= 1 or die "can only check for one type at a time")
}

In the body of the routine we can use junctions and smart matching to check if options are present.

my Bool $recursive = any(@options) ~~ Find::Recursive;
my %tests = Find::File => {so .f}, Find::Dir => {so .d}, Find::Symlink => {so .l};
@tests.append(%tests{@options.grep: * ~~ Find::Type});

The routine is then called with a list of flags at the end of it’s parameter list.

find(%*ENV<HOME>, include => {.extension eq 'txt'}, exclude => ['cfg', /.xml $/] , Find::File, Find::Recursive, Find::Keep-going);

The same would be possible to do with named arguments but I can’t see a way to do the exclusiveness in a where-clause. I like to have as much argument processing in the signature because it makes it easy to write documentation. Separate all arguments with a newline and then translate type constraints and where-clauses into plain English. Also, having enums as flags feels quite 6-ish and that’s what this blog (post) is about.

Categories: Uncategorized

It’s lazy all the way down

August 14, 2016 4 comments

On my quest to help with the completion of the docs for Perl 6 I found the task to find undocumented methods quite cumbersome. There are currently 241 files that should contain method definitions and that number will likely grow with 6.d.

Luckily I wield the powers of Perl 6 what allows me to parse text swiftly and to introspect the build-in types.

71     my \methods := gather for types -> ($type-name, $path) {
72         take ($type-name, $path, ::($type-name).^methods(:local).grep({
73             my $name = .name;
74             # Some buildins like NQPRoutine don't support the introspection we need.
75             # We solve this the British way, complain and carry on.
76             CATCH { default { say "problematic method $name in $type-name" unless $name eq '<anon>'; False } }
77             (.package ~~ ::($type-name))
78         })».name)
79     }

We can turn a Str into a list of method objects by calling ::("YourTypeName").^methods(). The :local adverb will filter out all inherited methods but not methods that are provided by roles and mixins. To filter roles out we can check if the .package property of a method object is the same then the type name we got the methods from.

For some strange reason I started to define lazy lists and didn’t stop ’till the end.

52     my \ignore = LazyLookup.new(:path($ignore));

That creates a kind of lazy Hash with a type name as a key and a list of string of method names as values. I can go lazy here because I know the file those strings come from will never contain the same key twice. This works by overloading AT-KEY with a method that will check in a private Hash if a key is present. If not it will read a file line-by-line and store any found key/value pairs in the private Hash and stop when it found the key AT-KEY was asked for. In a bad case it has to read the entire file to the end. If we check only one type name (the script can and should be used to do that) we can go lucky and it wont pass the middle of the file.

54     my \type-pod-files := $source-path.ends-with('.pod6')

That lazy list produces IO::Path objects for every file under a directory that ends in ‘.pod6’ and descends into sub-directories in a recursive fashion. Or it contains no lazy list at all but a single IO::Path to the one file the script was asked to check. Perl 6 will turn a single value into a list with that value if ever possible to make it easy to use listy functions without hassle.

64     my \types := gather for type-pod-files».IO {

This lazy list is generated by turning IO::Path into a string and yank the type name out of it. Type names can be fairly long in Perl 6, e.g. X::Method::Private::Permission.

71     my \methods := gather for types -> ($type-name, $path) {

Here we gather a list of lists of method names found via introspection.

81     my \matched-methods := gather for methods -> ($type-name, $path, @expected-methods) {

This list is the business end of the script. It uses Set operators to get the method names that are in the list created by introspection (methods that are in the type object) but neither in the pod6-file nor in the ignore-methods file. If the ignore-methods is complete and correct, that will be a list of methods that we missed to write documentation for.

88     for matched-methods -> ($type-name, $path, Set $missing-methods) {
89         put "Type: {$type-name}, File: ⟨{$path}⟩";
90         put $missing-methods;
91         put "";
92     };

And then at the end we have a friendly for loop that takes those missing methods and puts them on the screen.

Looking at my work I realised that the whole script wouldn’t do squad all without that for loop. Well, it would allocate some RAM and setup a handful of objects, just to tell the GC to gobble them all up. Also there is a nice regularity with those lazy lists. They take the content of the previous list, use destructuring to stick some values into input variables that we can nicely name. Then it declares and fills a few output variables, again with proper speaking names, and returns a list of those. Ready to be destructured in the next lazy list. I can use the same output names as input names in the following list what makes good copypasta.

While testing the script and fixing a few bugs I found that any mistake I make that triggers and any pod6-file did terminate the program faster then I could start it. I got the error message I need to fix the problem as early as possible. The same is true for bugs that trigger only on some files. Walking a directory tree is not impressively fast yet, as Rakudo creates a lot of objects based on c-strings that drop out of libc, just to turn them right back into c-strings when you asked for the content of another directory of open a file. No big deal for 241 files, really, but I did have the pleasure to $work with an archive of 2.5 million files before. I couldn’t possibly drink all that coffee.

I like to ride the bicycle and as such could be dead tomorrow. I better keep programming in a lazy fashion so I get done as much as humanly possible.

EDIT: The docs where wrong about how gather/take behaves at the time of the writing of this blog post. They are now corrected what should lead to less confusion.

Categories: Uncategorized

Sneaky methods

July 20, 2016 1 comment

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.

Categories: Uncategorized

It’s blocks all the way down

July 19, 2016 1 comment

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. :)

Categories: Uncategorized

Disecting subsets

July 17, 2016 1 comment

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.

Categories: Uncategorized

I don’t need conditionals either

July 17, 2016 4 comments

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.

Categories: Uncategorized