Tag: Raku

  • Perl lightning talk: ​“Don’t Fear map and grep”

    This week’s Perl and Raku Conference 2022 in Houston was packed with great pre­sen­ta­tions, and I humbly added to them with a five-​ish minute light­ning talk on two of Perl’s more mis­un­der­stood func­tions: map and grep.

    Sorry about the ​”um”s and ​”ah”s…

    I’ve writ­ten much about list pro­cess­ing in Perl, and this talk was based on the fol­low­ing blog posts:

    Overall I loved attend­ing the con­fer­ence, and it real­ly invig­o­rat­ed my par­tic­i­pa­tion in the Perl com­mu­ni­ty. Stay tuned as I resume reg­u­lar posting!

    Update for Raku

    On Twitter I nudged promi­nent Raku hack­er (and recov­ered Perl hack­er) Elizabeth Mattijsen to write about the Raku pro­gram­ming language’s map and grep func­tion­al­i­ty. Check out her five-​part series on DEV.to.

  • This week: The ePhEmeRaL miniconf

    This week: The ePhEmeRaL miniconf

    After a lot of pro­cras­ti­na­tion, I’ve decid­ed my talk for this week’s ePhEmeRaL mini­conf will be ​“Cunningham’s Law: A Year of Being Wrong on the Internet, or «prêch­er le faux pour savoir le vrai.»”

    The event starts at 8:00 AM CST on Thursday, November 18; you can find out more about it includ­ing the full sched­ule and a time zone con­vert­er here.

  • Frenemies part 2: What a difference a (Perl) module makes

    Frenemies part 2: What a difference a (Perl) module makes

    Last week I explored using the Inline::Perl5 mod­ule to port a short Perl script to Raku while still keep­ing its Perl depen­den­cies. Over at the Dev.to com­mu­ni­ty, Dave Cross point­ed out that I could get a bit more bang for my buck by let­ting his Feed::Find do the heavy lift­ing instead of WWW::Mechanize​’s more general-​purpose parsing.

    A lit­tle more MetaCPAN inves­ti­ga­tion yield­ed XML::Feed, also main­tained by Dave, and it had the added ben­e­fit of obvi­at­ing my need for XML::RSS by not only dis­cov­er­ing feeds but also retriev­ing and pars­ing them. It also han­dles the Atom syn­di­ca­tion for­mat as well as RSS (hi dax­im!). Putting it all togeth­er pro­duces the fol­low­ing much short­er and clear­er Perl:

    #!/usr/bin/env perl
    
    use v5.12; # for strict and say
    use warnings;
    use XML::Feed;
    use URI;
    
    my $url = shift @ARGV || 'https://phoenixtrap-com.us.stackstaging.com';
    
    my @feeds = XML::Feed->find_feeds($url);
    my $feed  = XML::Feed->parse( URI->new( $feeds[0] ) )
        or die "Couldn't find a feed at $url\n";
    
    binmode STDOUT, ':encoding(UTF-8)';
    say $_->title, "\t", $_->link for $feed->entries;

    And here’s the Raku version:

    #!/usr/bin/env raku
    
    use XML::Feed:from<Perl5>;
    use URI:from<Perl5>;
    
    sub MAIN($url = 'https://phoenixtrap-com.us.stackstaging.com') {
        my @feeds = XML::Feed.find_feeds($url);
        my $feed  = XML::Feed.parse( URI.new( @feeds.first ) )
            or exit note "Couldn't find a feed at $url";
    
        put .title, "\t", .link for $feed.entries;
    }

    It’s even clos­er to Perl now, though it’s using the first rou­tine rather than sub­script­ing the @feeds array and leav­ing off the the $_ vari­able name when call­ing meth­ods on it—less punc­tu­a­tion noise often aids read­abil­i­ty. I also took a sug­gest­ed exit idiom from Raku devel­op­er Elizabeth Mattijsen on Reddit to sim­pli­fy the con­tor­tions I was going through to exit with a sim­ple mes­sage and error code.

    There are a cou­ple of lessons here:

    • A lit­tle more effort in mod­ule shop­ping pays div­i­dends in sim­pler code.
    • Get feed­back from far and wide to help improve your code. If it’s for work and you can’t release as open-​source, make sure your code review process cov­ers read­abil­i­ty and maintainability.
  • Perl & Raku: Best frenemies

    Perl & Raku: Best frenemies

    The Perl and Raku pro­gram­ming lan­guages have a com­pli­cat­ed his­to­ry togeth­er. The lat­ter was envi­sioned in the year 2000 as Perl 6, a com­plete redesign and rewrite of Perl to solve its prob­lems of dif­fi­cult main­te­nance and the bur­den of then-​13 years of back­ward com­pat­i­bil­i­ty. Unfortunately, the devel­op­ment effort towards a first major release dragged on for ten years, and some devel­op­ers began to believe the delay con­tributed to the decline of Perl’s market- and mind­share among pro­gram­ming languages.

    In the inter­ven­ing years work con­tin­ued on Perl 5, and even­tu­al­ly, Perl 6 was posi­tioned as ​“a sis­ter lan­guage, part of the Perl fam­i­ly, not intend­ed as a replace­ment for Perl.” Two years ago it was renamed Raku to bet­ter indi­cate it as a dif­fer­ent project.

    Although the two lan­guages aren’t source-​compatible, the Inline::Perl5 mod­ule does enable Raku devel­op­ers to run Perl code and use Perl mod­ules with­in Raku, You can even sub­class Perl class­es in Raku and call Raku meth­ods from Perl code. I hadn’t real­ized until recent­ly that the Perl sup­port was so strong in Raku despite them being so dif­fer­ent, and so I thought I’d take the oppor­tu­ni­ty to write some sam­ple code in both lan­guages to bet­ter under­stand the Raku way of doing things.

    Rather than a sim­ple ​“Hello World” pro­gram, I decid­ed to write a sim­ple syn­di­cat­ed news read­er. The Raku mod­ules direc­to­ry didn’t appear to have any­thing com­pa­ra­ble to Perl’s WWW::Mechanize and XML::RSS mod­ules, so this seemed like a great way to test Perl-​Raku interoperability.

    Perl Feed Finder

    First, the Perl script. I want­ed it smart enough to either direct­ly fetch a news feed or find it on a site’s HTML page.

    #!/usr/bin/env perl
    use v5.24;    # for strict, say, and postfix dereferencing
    use warnings;
    use WWW::Mechanize;
    use XML::RSS;
    use List::Util 1.33 qw(first none);
    my @rss_types = qw<
        application/rss+xml
        application/rdf+xml
        application/xml
        text/xml
    >;
    my $mech = WWW::Mechanize->new;
    my $rss  = XML::RSS->new;
    my $url = shift @ARGV || 'https://phoenixtrap-com.us.stackstaging.com';
    my $response = $mech->get($url);
    # If we got an HTML page, find the linked RSS feed
    if ( $mech->is_html
        and my @alt_links = $mech->find_all_links( rel => 'alternate' ) )
    {
        for my $rss_type (@rss_types) {
            $url = ( first { $_->attrs->{type} eq $rss_type } @alt_links )->url
                and last;
        }
        $response = $mech->get($url);
    }
    die "$url does not have an RSS feed\n"
        if none { $_ eq $response->content_type } @rss_types;
    binmode STDOUT, ':encoding(UTF-8)';    # avoid wide character warnings
    my @items = $rss->parse( $mech->content )->{items}->@*;
    say join "\t", $_->@{qw<title link>} for @items;

    In the begin­ning, you’ll notice there’s a bit of boil­er­plate: use v5.24 (released in 2016) to enable restrict­ing unsafe code, the say func­tion, and post­fix deref­er­enc­ing to reduce the noise from nest­ed curly braces. I’m also bring­ing in the first and none list pro­cess­ing func­tions from List::Util as well as the WWW::Mechanize web page retriev­er and pars­er, and the XML::RSS feed parser.

    Next is an array of pos­si­ble media (for­mer­ly MIME) types used to serve the RSS news feed for­mat on the web. Like Perl and Raku, RSS for­mats have a long and some­times con­tentious his­to­ry, so a news­read­er needs to sup­port sev­er­al dif­fer­ent ways of iden­ti­fy­ing them on a page.

    The pro­gram then cre­ates new WWW::Mechanize (called a mech for short) and XML::RSS objects for use lat­er and gets a URL to browse from its command-​line argu­ment, default­ing to my blog if it has none. (My site, my rules, right?) It then retrieves that URL from the web. If mech believes that the URL con­tains an HTML page and can find link tags with rel="alternate" attrib­ut­es pos­si­bly iden­ti­fy­ing any news feeds, it then goes on to check the media types of those links against the ear­li­er list of RSS types and retrieves the first one it finds.

    Next comes the only error check­ing done by this script: check­ing if the retrieved feed’s media type actu­al­ly match­es the list defined ear­li­er. This pre­vents the RSS pars­er from attempt­ing to process plain web pages. This isn’t a large and com­pli­cat­ed pro­gram, so the die func­tion is called with a trail­ing new­line char­ac­ter (\n) to sup­press report­ing the line on which the error occurred.

    Finally, it’s time to out­put the head­lines and links, but before that hap­pens Perl has to be told that they may con­tain so-​called ​“wide char­ac­ters” found in the Unicode stan­dard but not in the plain ASCII that it nor­mal­ly uses. This includes things like the typo­graph­i­cal ​‘curly quotes’ that I some­times use in my titles. The last two lines of the script loop through the parsed items in the feed, extract­ing their titles and links and print­ing them out with a tab (\t) sep­a­ra­tor between them:

    Output from feed_finder.pl

    Raku Feed Finder

    Programming is often just stitch­ing libraries and APIs togeth­er, so it shouldn’t have been sur­pris­ing that the Raku ver­sion of the above would be so sim­i­lar. There are some sig­nif­i­cant (and some­times wel­come) dif­fer­ences, though, which I’ll go over now:

    #!/usr/bin/env raku
    use WWW::Mechanize:from<Perl5>;
    use XML::RSS:from<Perl5>;
    my @rss_types = qw<
      application/rss+xml
      application/rdf+xml
      application/xml
      text/xml
    >;
    my $mech = WWW::Mechanize.new;
    my $rss  = XML::RSS.new;
    sub MAIN($url = 'https://phoenixtrap-com.us.stackstaging.com') {
        my $response = $mech.get($url);
        # If we got an HTML page, find the linked RSS feed        
        if $mech.is_html {
            my @alt_links = $mech.find_all_links( Scalar, rel => 'alternate' );
            $response = $mech.get(
                @alt_links.first( *.attrs<type> (elem) @rss_types ).url
            );
        }
        if $response.content_type(Scalar) !(elem) @rss_types {
            # Overriding Raku's `die` stack trace is more verbose than we need
            note $mech.uri ~ ' does not have an RSS feed';
            exit 1;
        }
        my @items = $rss.parse( $mech.content ).<items>;
        put join "\t", $_<title link> for @items;
    }

    The first thing to notice is there’s a bit less boil­er­plate code at the begin­ning. Raku is a younger lan­guage and doesn’t have to add instruc­tions to enable less backward-​compatible fea­tures. It’s also a larg­er lan­guage with func­tions and meth­ods built-​in that Perl needs to load from mod­ules, though this feed find­er pro­gram still needs to bring in WWW::Mechanize and XML::RSS with anno­ta­tions to indi­cate they’re com­ing from the Perl5 side of the fence.

    I decid­ed to wrap the major­i­ty of the pro­gram in a MAIN func­tion, which hand­i­ly gives me command-​line argu­ments as vari­ables as well as a usage mes­sage if some­one calls it with a --help option. This is a neat quality-​of-​life fea­ture for script authors that clev­er­ly reuses func­tion sig­na­tures, and I’d love to see this avail­able in Perl as an exten­sion to its sig­na­tures feature.

    Raku and Perl also dif­fer in that the for­mer has a dif­fer­ent con­cept of con­text, where an expres­sion may be eval­u­at­ed dif­fer­ent­ly depend­ing upon whether its result is expect­ed to be a sin­gle val­ue (scalar) or a list of val­ues. Inline::Perl5 calls Perl func­tions in list con­text by default, but you can add the Scalar type object as a first argu­ment to force scalar con­text as I’ve done with calls to find_​all_​links (to return an array ref­er­ence) and content_​type (to return the first para­me­ter of the HTTP Content-​Type header).

    Another inter­est­ing dif­fer­ence is the use of the (elem) oper­a­tor to deter­mine mem­ber­ship in a set. This is Raku’s ASCII way of spelling the ∈ sym­bol, which it can also use; !(elem) can also be spelled ∉. Both are hard to type on my key­board so I chose the more ver­bose alter­na­tive, but if you want your code to more close­ly resem­ble math­e­mat­i­cal nota­tion it’s nice to know the option is there.

    I also didn’t use Raku’s die rou­tine to exit the pro­gram with an error, main­ly because of its method of sup­press­ing the line on which the error occurred. It requires using a CATCH block and then key­ing off of the type of excep­tion thrown in order to cus­tomize its behav­ior, which seemed like overkill for such a small script. It would have looked some­thing like this:

    {
        die $mech.uri ~ ' does not have an RSS feed'
            if $response.content_type(Scalar) !(elem) @rss_types;
        CATCH {
            default {
                note .message;
                exit 1;
            }
        }
    }

    Doubtless, this could be golfed down to reduce its ver­bosi­ty at the expense of read­abil­i­ty, but I didn’t want to resort to clever tricks when try­ing to do a one-​to-​one com­par­i­son with Perl. More expe­ri­enced Raku devel­op­ers are wel­come to set me straight in the com­ments below.

    The last dif­fer­ence I’ll point out is Raku’s wel­come lack of deref­er­enc­ing oper­a­tors com­pared to Perl. This is due to the former’s con­cept of con­tain­ers, which I’m still learn­ing about. It seems to be fair­ly DWIMmy so I’m not that wor­ried, but it’s nice to know there’s an under­stand­able mech­a­nism behind it.

    Overall I’m pleased with this first ven­ture into Raku and I enjoyed what I’ve learned of the lan­guage so far. It’s not as dif­fer­ent with Perl as I antic­i­pat­ed, and I can fore­see cod­ing more projects as I learn more. The com­mu­ni­ty on the #raku IRC chan­nel was also very friend­ly and help­ful, so I’ll be hang­ing out there as time permits.

    What do you think? Can Perl and Raku bet­ter learn to coex­ist, or are they des­tined to be rivals? Leave a com­ment below.