Some tricks for prettier xs

XS has a reputation of being ugly and cumbersome, but in my experience, it doesn't have to be. Let's take for example this snippet from my Thread::Csp::Promise class:

MODULE = Thread::Csp PACKAGE = Thread::Csp::Promise PREFIX = promise_

SV* promise_get(Promise* promise)

bool promise_is_finished(Promise* promise)

SV* promise_get_notifier(Promise* promise)

My new modules in 2021

Perl

I had a reasonably productive year, releasing several modules that I think/hope are useful for the wider ecosystem.

Crypt::Passphrase

This module manages the passwords in a cryptographically agile manner. That means that it can not only verify passwords using different ciphers, but it also aids in gradually upgrading passwords hashed with an outdated cipher (or outdated settings) to the current one; for example when you want to upgrade from bcrypt to argon2. Password hashing is both a rather common form of cryptography, and one that is more subject to change than others; you should probably reevaluate your password handling every couple of years. With this module, you can initiate such a transition with a simple configuration change.

This also includes a number of extension distributions (e.g. Crypt::Passphrase::Argon2, Crypt::Passphrase::Bcrypt, etc…), and one new backend module (Crypt::Bcrypt)

Thread::Csp

My most ambitious project of the year by far. It's actually been in the making for a decade, full of lessons learned in my previous attempt. Thread::Csp is a new threading library (build on ithreads primitives, but not on threads.pm and doesn't clone whole interpreters); it is based on Communicating Sequential Processes (hence the name), the same model that Go uses (in particular for its channels).

I firmly believe share-nothing message-passing models of multi-threading are the overlap between what is useful and what is realistically possible given the current interpreter.

autocroak

This is essentially an autodie replacement with one important difference: it's based on opcode overrides instead of function overrides. This means not only that it interacts better with other pragmas, but also that it can support keywords that can not easily be overriden (such as print and system). It should also give less weird edge-cases than autodie.

Raku

I didn't produce as much Raku code this year, most of my Raku energy went into writing a series of blog posts that eventually I made a conference presentation instead.

Crypt::Passphrase

This was a port of the previously mentioned Perl module. It doesn't quite have the backend ecosystem that its big brother has, but given that there's a lot less legacy software in Raku that's not all that much of a problem.

Net::MQTT

A friend complained about the lack of MQTT support in Raku, and binary protocols just happen to be something I have a lot of experience with, so I implemented an MQTT client. While arguably this is the least useful module of the bunch, it was the most fun to write. Raku's typesystem and integrated event loop made this experience a lot smoother than they would have been in other languages.

The Witch and the Witch-hunt

A lot has been said about the recent CAT report and updates. It feels to me like we're not getting anywhere because the critical matters aren't being addressed.

Perl7 is a fork of values

Before reading this, you should watch this video where Bryan Cantrill explains a value-conflict between Joyent and Node.js, I believe we have a similar problem.

In it he defines a list of project values:

values

All these values are important - but they are in tension. In the end one has to choose between them.

Perl's has traditionally prioritized certain values over these others, and in my experience these are:

  • Expressiveness
  • Extensibility
  • Stability

Perl 7, not quite getting better yet

Hegel remarks somewhere that all great world-historic facts and personages appear, so to speak, twice. He forgot to add: the first time as tragedy, the second time as farce.

The Eighteenth Brumaire of Louis Napoleon - Karl Marx

Sawyer just announced his plans for perl 7. And while Perl 7 sounds like a lovely language, I do see a number of issues:

Cohabitation / Forking

The proposal is presented as a linear progress, I don't believe this is realistic. This would be fork much like the python 3 transition is (which also wanted to be a simple linear progression). As we all know, they're currently in year 12 of a 5 year transition.

There are several problems here. CPAN as an ecosystem is the one that is given most attention to (not without reason; it is without doubt the most important collection of Perl code), but it's not even the biggest problem.

The biggest problem is that /usr/bin/perl is infrastructure. We can't do breaking changes to its basic functionality for the same reason that shell and awk can't. Too many things in too many places are dependent on it, from system administration scripts to bioinformatics workflows to build systems (e.g. autotools, postgresql) and many more.

And this change is vastly breaking. Enabling strict and disabling prototypes (to make way for signatures) will break vast amounts of code, especially in the scripting domain of perl. It's quite telling that 12 years after python3 was released /usr/bin/python isn't a python3 by default on any of the big distributions (Ubuntu, Debian, Fedora, Red Hat, OpenSuse); and arguably python is less entrenched than perl is. I don't believe that /usr/bin/perl will ever be perl7. That means that perl7 can only meaningfully exist if it's set up to coexist alongside of perl5 for a very long time. And that actually comes with a number of challenges that may not seem obvious at first (e.g. colliding script names and man pages).

Releasing a Perl7 will not erase perl5. Perl5 will in all likelihood remain the Perl that's available on any platform regardless of how successful perl7 will be.

Perl 8 and beyond

Major version transitions are costly, and often traumatic (Perl 6 and Python 3 being obvious examples). Communities also take a lot of time catching up with them (again, see above examples); at least a decade if not more.

A big, breaking release is something a mature programming language can only do once per decade or so; anything else would result in two transitions going on at the same time. We shouldn't even be thinking about a perl8 this decade, let alone a perl9. If we are to do a perl7, we must get it right the first time. And I don't think this plan is quite getting it right. And quite frankly, I can't imagine any reason for wanting to do a big breaking release if we'd do 7 right.

We are not ready

The current plan is essentially Enable all non-controversial features by default, and I don't think that that is the best we can do. There are a lot of features that haven't been implemented before because they don't make much sense in a minor release (in particularly the kind that removes syntax like no feature 'indirect'). Releasing it now will force a perl8 relatively soon, and that would be undesirable for all the reasons stated above.

Manpower

We have been failing at shipping non-experimental signatures for more than half a decade now, why would we be able to ship a perl 7? The most significant new feature that made it out of experimental in the past half decade was postfix dereferencing, and while welcome it's not quite a game changer.

Sadly, the most convincing reason not to go through with this may very well be "we may not be able to". I think we need to figure out what problems we can resolve before deciding to actually go forward with this.

Timescale

There's just no way we can do all of the above before the end of the year for a variety of reasons. Not only because it will require adaptations on the perl5 side to enable cohabitation, but also because we will need to sort out a lot of details. Trying to rush is likely to result in a failure, and is not something we can afford. I can't imagine any way of successfully doing this that doesn't involve releasing a v5.34 first (and possibly more).

Then don't upgrade?

The if you don't want your code to break then don't upgrade argument is rather assuming users have a firm control over which perl they are running. This is generally true for million line perl web applications, but this is not true for system perl.

If our objective is to limit ourselves to perlbrew/perlbuild/etc…, many of my objections become moot. But I don't think that should be the target, I think that would exclude a wide range of applications. So no, I don't think saying "then don't upgrade" really solves that problem. We may be able to postpone the problem, but it won't go away by itself.

The absentee/maintainer dichotomy

I do not recognize this distinction at all. Just because I actively maintain my stuff doesn't mean I want to be dealing with other people breaking my code. If I wanted to deal with the whims of a platform breaking trivial things I'd be programming python.

Associating not wanting the language to break with diminishing use of the language is perplexing to me. Perl is a language of which a lot has been written already, and relative to that past popularity not all that much new code is being written. Quite a lot of Perl strongholds are attributable to Perl not breaking, it's uncertain if the pain of this process will be worth the gain.

There's also this suggestion that people who care about backwards compatibility contribute less to the language. This isn't actually explained further but it seems like a rather bold statement to me.

Whom are we serving?

Perl has many different types of users, with many different needs. This is inherent to a language that tries to be useful at 1 line and at 1 million lines.

The argument that has been made in the keynote suggests that the only reason why one would use "old-style Perl" is because you've abandoned your code, and I don't think that is true. Many best practices that are essential when writing large applications are not nearly as valuable in a small script; it would be outright silly to suggest one-liners need strict.

The changes that are proposed are largely serving the manipulexity end of the spectrum. And this is an important user base, but it's not our only user base. For the whipuptitude end of the spectrum, the scripters, this represents their code breaking without them getting anything in return. That is the priority that is being chosen here.

Bad code

I believe this "bad pattern" rhetoric is flawed. Ultimately the only good code is working code, and the only bad code is code that doesn't get the job done. What I hear being described as bad code is actually merely ugly code. And this transition can break stuff for people, and breaking code is bad, whereas ugly code is only a problem to me if it ends up on my plate.

How did we get into this brave new world where one calls judgment on users and deplatforming the ones deemed bad?

This reminds me of a bioinformatician I met at a recent TPC. Was their code strict? No. Did it get the job done? Yes. Why would they care if we in the echo chamber approve of her code, they have more important things to do, like curing ovarian cancer. In my book, they got their priorities straight.

Is this really worth it?

This seems like a lot of pain, just to avoid having to type use v5.32. The real problem of course is that that doesn't only not enable warnings (which we can easily fix for 5.34), but it also doesn't enable signatures (probably the recent feature people care most about). If we can make use v5.34 do those two things, I don't think I need a perl7, even if I understand why some other people feel they do want it. Boilerplate may be annoying, but one line of boilerplate in every file is way more tolerable to me than the pain of a fork.

This was Jesse Vincent's vision 9 years ago, and I still think this is the right trade-off for a platform like Perl.