Archive

Author Archive

Hunting Documented Bugs

September 2, 2017 1 comment

AlexDaniel came up with and Zoffix made some propaganda for a reoccuring bug hunt. This weeks pray are doc issues. In the following are detailed instructions on how to get dressed up.

zef install META6::bin
meta6 --fork-module=p6doc
cd doc
zef --deps-only install .
# you may have to add $HOME/.perl6/bin to $PATH
# edit away
git push
meta6 --pull-request --title='add t/meta.t'
# goto edit away

If you never used META6::bin you may have to do some setup.

Advertisements
Categories: Perl6

Out of Order Mystery

August 27, 2017 1 comment

Judging by our irc logs Proc::Async seams not to be well documentent. In the following I shall procide some answers and hopefully raise the missing questions so we can fill another few holes in the docs.

First some code with line numbers.

      1 #! /usr/bin/env perl6
      2
      3 use v6.c;
      4
      5 my $line-source = Proc::Async.new("perl6", "bin/line-source.p6", :w);
      6
      7
      8 react {
      9     whenever $line-source.stdout -> $l is copy {
     10         $line-source.put: $l++;
     11         # die "ouch!" if $++ > 100;
     12     }
     13     whenever $line-source.start {
     14         say "exitcode: ", .exitcode; done
     15     }
     16     whenever signal(SIGINT) {
     17         say "sigint: $_";
     18         $line-source.close-stdin;
     19         exit 0
     20     }
     21     whenever Promise.in(5) {
     22         note "timeout";
     23         $line-source.kill;
     24     }
     25     whenever Promise.in(2) { $line-source.put: 1 }
     26
     27     CONTROL { say "control: $_"; }
     28     CATCH { say .^name, ': ', .Str; }
     29     LEAVE { say "LEAVE"; }
     30     CLOSE { say "CLOSE"; }
     31 }

And now the order of execution of those lines.

Any line with a whenever statement is executed in the order given but the whenever block itself is delayed. Think of it as a setup phase.

The first line executed in the react block is the leave block in line 29. The whole point of a react block is to add one or many invisible awaits that take over control flow inside the block. Any exception fired inside any whatever and the surrounding react block will be handled in the CATCH block of line 28. If any exception is forcing any Supply to be closed, the CLOSE block will be run. Normal execution wont (this may be a bug).

If no odd things happend, line 10 is run whenever a newline shows up in STDOUT. The signal handler at line 17 is fired when the signal is processed (that can take a bit). The timeout of 5 seconds may take more then 5 seconds but it will close STDIN and as such force line 14 to be executed. If the program started in line 13 exits on its own, line 14 will be run as well.

The block in line 25 is executed after at least 2 seconds after setup.

There are likely bits I missed. Your questions are very welcome. I for one need rest now to get my brain back in order.

UPDATE: There is no timeout for reads from buffered programs. So if they don’t have a timeout on their own, they may hang until STDIN is closed.

Categories: Perl6

Preparations for your

August 20, 2017 1 comment

In his excellent speech Damian Conway showed how to implement a new declarator he called your that will output any value change to the container for debugging. The whole thing made me worry that Perl 5 might overtake Perl 6 causing even more naming confusion as we got already. So I set out to get us ahead a little again.

We can’t easily implement declarators in Perl 6 yet but fancy containers are no problem. All we need is a Proxy that does a type check. The latter can be achived with a type capture in the constructor.

class Watched {
    has Mu $.container is rw;
    my $quote-start = '⟨';
    my $quote-end = '⟩';

    method new(::T, :$name = '<unnamed>') {
        my $self = self.bless(:container(T));
        Proxy.new(
            FETCH => method () { $self.container },
            STORE => method (T $new-value) {
                temp $quote-start;
                temp $quote-end;
                if $*ERR.t {
                    $quote-start := "\e[7m";
                    $quote-end := "\e[0m";
                }
                note "Container $name changed from {$quote-start ~ $self.container.gist ~ $quote-end} to {$quote-start ~ $new-value ~ $quote-end}";
                $self.container = $new-value
            }
        )
    }
}

The get a container stick we need to use binding. Sadly without proper macro support there is no way to get hold of the container name automatically because Proxy does not support the same interface as Scalar. At the other hand providing it manuelly gives a little more flexibility.

my $c := Watched.new(Int, :name<$c>);

dd $c; # Int
$c = 42; # STDERR: Container $c changed from (Int) to 42
dd $c; # 42

I hope to have shown that one more level of indirection works equally well in Perl 5 and Perl 6.

UPDATE: If we output to STDERR we better test if $*ERR is a tty.

Categories: Perl6

Parsing Nothing

August 17, 2017 3 comments

In Git::Config I made the assumption that when there is nothing to parse there is nothing to do. The code looked as follows.

my $parsed = Config.parse($cfg-text);

for $parsed.Hash<section>.list -> $section {
    # [...]
}

A recent change in Rakudo broke that assumption. Parsing an empty file with a grammar that isn’t prepared to return nothing will return Failure instead of Nil now. As it turns out for doesn’t like to loop over an instance of Failure. There is an easy fix because Failures are undefined.

my $parsed = Config.parse($cfg-text) // [];

For your use cases it may make more sense to use // Nil instead to get the old behaviour back. In any case I would like to ask you check your modules for assumptions reguarding .parse or help travis to help you.

Categories: Perl6

On good terms with constants

August 13, 2017 1 comment

While building a little helper module to fetch internet radio stations I found myself wanting to provide a constant named parameter. Quite a few methods of DateTime have a named argument when $*TZ would be wrong. As it turns out, this is really easy in Perl 6.

constant term:<GMT> = timezone => 0;
say DateTime.now(|GMT)

The term GMT is still a Pair so we have to slip it in but it’s still a bit shorter and more expressive once one gets used to the idea of constant Pair terms.

Categories: Perl6

Issue All The Things

April 30, 2017 1 comment

While on her epic quest to clean up the meta part of the ecosystem samvc send me a few pull requests. That raised the question which of my modules have open issues. Github is quite eager to list you many things but lacks the ability to show issues for a group of repos. Once again things fell into place.

Some time ago I made a meta module to save a few clicks when testing modules once a week. What means I have a list of modules I care about already.

perl6 -e 'use META6; use META6::bin :TERM :HELPER;\\
for META6.new(file => "$*HOME/projects/perl6/gfldex-meta-zef-test/META6.json").<depends> -> $name {\\
    say BOLD $name;\\
}'

META6::bin didn’t know about Github issues, what was easily solved, including retries on timeouts of the github api. Now I can feed the module names into &MAIN and get a list of issues.

perl6 -e 'use META6; use META6::bin :TERM :HELPER;\\
for META6.new(file => "$*HOME/projects/perl6/gfldex-meta-zef-test/META6.json").<depends> -> $name {\\
    say BOLD $name;\\
    try META6::bin::MAIN(:issues, :module($name), :one-line, :url);\\
}'

I switfly went to merge the pull requests.

Test::META
[open] Add License checks and use new META license spec [10d] ⟨https://github.com/jonathanstowe/Test-META/pull/21⟩
[open] warn on source [35d] ⟨https://github.com/jonathanstowe/Test-META/issues/20⟩
[open] warn on empty description [37d] ⟨https://github.com/jonathanstowe/Test-META/issues/19⟩
[open] check if source-url is accessible [37d] ⟨https://github.com/jonathanstowe/Test-META/issues/18⟩
[open] Check `perl` version [135d] ⟨https://github.com/jonathanstowe/Test-META/issues/14⟩
[open] Report missing modules? [1y] ⟨https://github.com/jonathanstowe/Test-META/issues/8⟩
[open] Add :strict-versions switch [1y] ⟨https://github.com/jonathanstowe/Test-META/issues/7⟩
[open] Test harder that "provides" is sane [1y] ⟨https://github.com/jonathanstowe/Test-META/issues/6⟩
Typesafe::XHTML::Writer
Rakudo::Slippy::Semilist
Slippy::Semilist
Github timed out, trying again 1/3.
Github timed out, trying again 2/3.
Github timed out, giving up.
Operator::defined-alternation
Concurrent::Channelify
[open] Use SPDX identifier in license field of META6.json [3d] ⟨https://github.com/gfldex/perl6-concurrent-channelify/pull/1⟩
Concurrent::File::Find
[open] Use SPDX identifier in license field of META6.json [3d] ⟨https://github.com/gfldex/perl6-concurrent-file-find/pull/1⟩
XHTML::Writer
Github timed out, trying again 1/3.
Typesafe::HTML
Git::Config
Proc::Async::Timeout
Github timed out, trying again 1/3.
[open] Use SPDX identifier in license field of META6.json [9d] ⟨https://github.com/gfldex/perl6-proc-async-timeout/pull/1⟩

To check the issues of any project that got a META6.json run meta6 --issues. To check if there are issues for a given module in the ecosystem use meta6 --issues --module=Your::Module::Name

UPDATE:

As requested by timotimo, meta6 --issues --one-line --url --deps will list all issues of the repo and all issues of the dependencies listed in META6.json.

Categories: Uncategorized

You can call me Whatever you like

April 19, 2017 1 comment

The docs spend many words to explain in great detail what a Whatever is and how to use it from the caller perspective. There are quite a few ways to support Whatever as a callee as I shall explain.

Whatever can be used to express “all of the things”. In that case we ask for the type object that is Whatever.

sub gimmi(Whatever) {};
gimmi(*);

Any expression that contains a Whatever * will be turned into a thunk. The latter happens to be a block without a local scope (kind of, it can be turned into a block when captured). We can ask specifically for a WhateverCode to accept Whatever-expressions.

sub compute-all-the-things(WhateverCode $c) { $c(42) }
say compute-all-the-things(*-1);
say (try say compute-all-the-things({$_ - 1})) // 'failed';
# OUTPUT: «41␤failed␤»

We could also ask for a Block or a Method as both come preloaded with one parameter. If we need a WhateverCode with more then one argument we have to be precise because the compiler can’t match a Callable sub-signature with a WhateverCode.

sub picky(WhateverCode $c where .arity == 2 || fail("two stars in that expession please") ) {
    $c.(1, 2)
}
say picky(*-*);
# OUTPUT: «-1␤»
say (try picky(*-1)) // $!;
# OUTPUT: «two stars in that expession please␤  in sub picky at …»

The same works with a Callable constraint, leaving the programmer more freedom what to supply.

sub picky(&c where .arity == 2) { c(1, 2) }

There are quite a few things a WhateverCode can’t do.

sub faily(WhateverCode $c) { $c.(1) }
say (try faily( return * )) // $!.^name;
# OUTPUT: «X::ControlFlow::Return␤»

The compiler can take advantage of that and provide compile time errors or get things done a little bit qicker. So trading the flexibility of Callable for a stricter WhateverCode constraint may make sense.

Categories: Uncategorized