A dream realized
Have you heard that they are finally putting together a proposal to add a clean modern OO system into the core of Perl?
If you haven’t, I strongly encourage you to look over the RFC for Corinna, or at least watch Ovid’s excellent presentation on the project.
It’s reassuring that the list of contributors to the proposed design includes some of the most highly respected names in the Perl community, many of whom have previously taken one (or more!) tilts at this particular object-oriented windmill.
Indeed, over the past two decades I too have repeatedly attempted to design and prototype richer and more robust OO systems for Perl, starting way back in the previous millennium with a brief stint as the maintainer of Class::Struct, and continuing on though the release of modules such as Class::Std, Class::Delegation, and most recently: Dios.
The Dios module represented almost everything I thought a comprehensive Perl OO system should contain. Not surprisingly, that actually meant it simply stole almost everything that Raku’s comprehensive OO system contains (mostly because I had spent quite a lot of time over the past two decades helping design that OO mechanism as well).
The only three problems with Dios are:
- It’s not built-in to Perl itself, so its performance is suboptional;
- It’s not built-in to Perl itself, so it requires a huge amount of extremely complex multi-layer code to make it feel as if is;
- It’s not built-in to Perl itself, so it's merely one possible choice amongst the vast and incoherent array of entirely reasonable alternatives already on CPAN.
That’s why, when people ask me whether I support the Corinna proposal, my response is: OH, HELL YES! I’ve literally been waiting two decades to see Perl gain a proper, built-in, declarative, encapsulated, and performant OO system. And this, I firmly believe, is it.
At this point I could launch into one of my usual extended exegeses on why this particular design is so exceptionally good, but I think two quick and specific examples are actually sufficient to explain my excitement about this proposal.
The first example is purely syntactic. If you were kind enough to watch the Three Little Words video in which I introduced Dios, you’ll have seen how that module vastly improves the syntax for declaring a Perl class. Instead of something like:
package Account {
use experimental 'signatures';
use Carp 'croak';
state $next_ID = 'AAA0001';
sub new($class, %arg) {
croak('Cannot specify ID as an constructor argument')
if exists $arg{ID};
bless {
name => $arg{name} // croak('Missing name arg'),
balance => $arg{balance} // 0,
ID => $next_ID++,
}, $class;
}
sub name ($self) {
return $self->{name};
}
sub set_name ($self, $newname) {
$self->{name} = $newname;
}
sub balance ($self) {
return $self->{balance};
}
sub ID ($self) {
return $self->{ID};
}
sub deposit ($self, $amount) {
$self->{balance} += $amount;
}
sub report ($self, $fh = *STDOUT) {
$fh->say( $self->ID . ': ' . $self->balance );
}
}
...Dios allows you to achieve exactly the same functionality with just:
use Dios;
class Account {
state $next_ID = 'AAA0001';
has $.name is rw is required;
has $.balance = 0;
has $.ID = $next_ID++;
method deposit ($amount) {
$balance += $amount;
}
method report ($fh = *STDOUT) {
$fh->say( "$ID: $balance" );
}
}
Not only is that three times less code, it’s three times simpler code, which means it’s also likely to be code that’s three times less buggy.
But what really excites me about Corinna is that, under that proposal, the same code would look like this:
use experimental 'class';
class Account {
state $next_ID = 'AAA0001';
slot $name :param :reader :writer;
slot $balance :param :reader = 0;
slot $ID :reader = $next_ID++;
method deposit ($amount) {
$balance += $amount;
}
method report ($fh = *STDOUT) {
$fh->say( "$ID: $balance" );
}
}
In other words: just as concise, just as readable, just as declarative. But without the huge behind-the-scenes overheads that Dios currently imposes.
The second example that illustrates why I’m so enthusiastic about the Corinna proposal is simply a subset of the first example. If we zoom in on that deposit()
method:
# under Corinna
method deposit ($amount) {
$balance += $amount;
}
...we can see an important improvement over the current standard Perl version:
# under standard Perl
sub deposit ($self, $amount) {
$self->{balance} += $amount;
}
...and an even greater improvement over what would be required under Moose or Moo or Object::InsideOut or most other existing OO frameworks:
# under most OO frameworks
sub deposit ($self, $amount) {
$self->balance( $self->balance + $amount );
}
Under Corinna, the slots of an object are accessed via simple scalar variables (e.g. $balance
) , not via a (slower) hash look-up (e.g. $self->{balance}
or via (much slower) accessor methods (e.g. $self->balance
).
This means that each individual slot access is going to be faster under Corinna, and so almost every method call will likewise be less expensive. For instance, each call to deposit()
is likely to be at least three times quicker than under any of the many OO frameworks, because we’re dispensing with the two additional embedded method calls to $self->balance()
.
More subtly, if we happened to misspell our slot variable:
# under standard Perl
sub deposit ($self, $amount) {
$self->{balence} += $amount;
# Silent bug (autovivifies useless 'balence' key)
}
# under most OO frameworks
sub deposit ($self, $amount) {
$self->balance( $self->balence + $amount );
# Runtime exception ("No such method 'balence'...")
}
# under Corinna
method deposit ($amount) {
$balence += $amount;
# Compile-time exception: ("No such variable: $balence...")
}
I don't know about you, but I'd much rather discover this problem the first time I compile the code, rather than at the first time it happens to actually be executed or, even worse, after a long and fruitless day of trying to debug the mysterious absence of recent deposit amounts.
There are so many other reasons to be enthusiastic about this proposed addition to standard Perl, not the least of which is that it will become standard and universally available, which may finally cut through the endless debate over whether your next project should use Moose or Moos or Moo or Mu or Spiffy or Object::InsideOut or Class::InsideOut or Class::Simple or Class::Easy or Class::Tiny or Class::Std or Dios or...
So, yes, I’m very excited about the RFC for Corinna, and I strongly encourage you to take a look for yourself at the powerful new OO features that will soon be proposed for Perl.
For the record, slots could be array or hashes too. That's also a huge win over using arrayrefs and hashrefs.
wow...most of example use scalar attribute, I don't know this!
Thanks for the nice summary, Damian.
Just too bad that Corinna doesn't use the syntax proposed in Dios (and used in Raku). That would have been simpler for people living in both worlds.
Fritz,
I think Dios is fantastic. However, making it and its syntax work for core in a way that P5P would be willing to commit to means stripping it down to an MVP, probably rewriting most of it in XS, and, ironically (which I'll explain in a moment), the twigils would likely be a blocker for adoption when it was first proposed—many people are violently against twigils.
The last point is ironic because we might adopt twigils for Corinna simply because they make life so much easier in terms of syntax highlighting, Huffman encoding of meaning, and avoiding variable shadowing.
When I started on Corinna, I had never considered Dios for core because of the scope of Dios (clearly not an MVP) and twigils. And yet here we are, potentially on the cusp of adding twigils (but the Perl parser had no support for the twigil syntax, so that's a huge change to add just for an experimental object system).
Best,
Ovid
Thanks for the explanation. I completely understand that trying to get Dios into core would be a (at least political) nightmare.
I just hope that differences to Raku syntax won't we a requirement for the actual implementation ;-) (not talking about you)
Hi Fritz,
> Corinna doesn't use the syntax proposed in Dios (and used in Raku).
I wonder if it's closer than you think?
First, the names of attributes (fields). Consider this Raku code:
In Raku, attributes declared `has $foo` are aliased to `$!foo`. (I could have written `$!balance` in the `deposit` method.)
(I would be happy to see Cor stick with `has $foo`. Especially if Perl did a better job with `our` variables than Raku has thus far, double especially if it was done in cooperation with Rakoons so Raku could pick up the same solution(s) to Raku's `our` problems.)
----
The second syntactic difference is also perhaps closer than you realize. This Cor code:
uses what, in Raku, is called "colon pair" notation. But it strikes me as consistent with Raku in just the right way, and *in*consistent in just the right way too.
First, it would be invalid syntax in Raku, and it jumps out as such. A nice reminder that one is reading Perl code.
Second, the Raku equivalent is to put something in exactly the same grammatical slot, but instead of writing a colon pair, write a verb (eg `is`) followed by... a colon pair! (With the leading colon omitted.)
So one just needs to translate from whatever Cor folk decide to name their colon pairs to what Raku folk decide. I agree it would be nice if they considered, for example, supporting `:rw` as short for `:read :write`. I mean, why not?
----
That all said, Raku *was* carefully designed. I'd say it would really behove Ovid et al to just ask Damian and Larry what they think about things the Cor team are wondering about.
I daresay Larry would feel a great deal of love if Ovid at least asked him about such things.
And if it's about the issue of huffmanizing attribute declarations to keep them private, and anything else that means syntax and semantics consistent with the actor model are embedded into Perl, I daresay it would not only pay back enormously in years to come in respect to love, but also to Perl's great technical advantage.
Personally, becuase package syntax is parsed by CPAN to get the package name, I want to respect the package syntax.
My idea is
package Foo is class {
}
or
package Foo : class {
}
How about this?
Hi Yuki,
We're trying very hard to avoid overloading the meaning of existing Perl features, so we deliberately didn't go with the word
package
. Thepackage
keyword simply declares something as being in a given namespace. Theclass
keyword in Corinna does the same thing, but it's a historical accident in Perl that classes and packages are sort of the same thing.In reality, a
class
is a data type, not a namespace. They're fundamentally different. While I don't know if it can be fixed, in the long-term, I would love to see the two ideas fully separated in Perl.Best,
Ovid
The opening comments argue that because some people have worked in this area for some time then their "authority" is enough to make the claim that Corinna is valuable. But this is a well known fallacy:
https://en.wikipedia.org/wiki/Argument_from_authority
If these people have genuine authority gained from years of hard experience in this field then they will be able to tell us in a few cogent words why Corinna is so much better than Moose and all the other OO systems available on CPAN. They will be able to tell us the mathematical theorems that underlie their work. They will be convincing. But a bald appeal to authority, is not only not convincing, it is also demeaning because it divides Perl people in to two classes, the "hoi poloi" whose thoughts on OO are not thought worth considering and a small remainder whose thoughts, apparently are so valuable that they do not even have to back up their ideas with indefeasible argumentation.
Please could you rewrite the start of this article so that we all know the compelling reasons why Corinna is so good: then the issues can be weighed on their merits genuine or otherwise rather relying on the mere assumption of authority.
I'm a little confused, Philip. You ask me to rewrite the article so that you can "know the compelling reasons why Corinna is so good"...but the article already contains at least six of those:
Of course, that is not an exhaustive list of all the benefits of the Corinna proposal, but I felt it was enough for a single article.
As for arguing from authority at the start of the article, I don't believe that's what I'm doing. Sure, I do mention that the project is a collaboration by a large number of people who are acknowledged experts in OO Perl, but I specifically say that I mention those contributors merely to reassure the reader, not as an argument in favour of Corinna.
After all, why would I expect the reader to even consider my subsequent arguments for this project, without first establishing that the proposal is likely to be worth their time and effort? Specifically, that it is not some random crazy idea, but has been designed by a group of people with a proven track record in the field.
Yes, arguing from authority is unquestionably fallacious. And, yes, if I had written (or even implied): "This proposal should be adopted because X, Y, and Z worked on it", then that would certainly be an invalid argument.
But simply pointing out that this project has the participation and support of a large number of experts is not the same as arguing for it from authority.
Rather, it's a way of quickly establishing that the project is a serious one, with a wide variety of experienced and credible contributors...before I launch into providing half a dozen actual reasons why it's worth your time to consider. And then conclude by explicitly urging you (and all my readers) to apply the only truly compelling assessment available to you: to investigate it yourself.
You're expending some hard won social credit on this endorsement of this latest attempt at POOP. For the sake of Perl, I hope you are hitching yourself to the correct attempt and not in some vain attempt to lend credit to the claim that, "POOP is not the problem, it's just never been implemented properly". Sounds like a familiar claim.