Perl and Me, Part 3: A Møøse once bit my sister
This is part 3 of an ongoing series where I explore my relationship with Perl. You may wish to begin at the beginning.
This week we look at the joys—and the frustrations—of Moose.
Last week I talked about why I believe that at least having the choice to program object-orientedly (without it being a huge pain in the ass) is vital to me as a programmer. In the comments I also touched briefly on why I think OOP in Perl, pre-Moose, is a huge pain in the ass, but honestly I didn’t put much effort into making that point. In my experience with other programmers (both in real life and online), the majority of them—perhaps 75%, at a rough guess—already agree with that and don’t need any convincing from me. And the rest are most likely not going to be convinced no matter what I say. Besides, this isn’t really a persuasive essay. I’m not trying to change anyone’s mind. It’s the story of my relationship with Perl. And I, like most other coders I know, have placed some value in OOP, at least in some circumstances. Also, I, like most other coders I know, felt that doing OOP in Perl was a bit of a chore.
Then we got Moose.
When I first heard of Moose, I was intrigued. After all, my primary exposure to OOP was via C++, and I’m sure many of you will have been thinking to yourselves this whole time: “but C++ isn’t even a very good implementation of OOP.” In fact, OOP purists regularly disparage C++. But I always liked it, in part because of its simplicity. It has its warts, obviously, but for the most part it Just Works. Moose, on the other hand, was a step up. Maybe not as hardcore OOP as, say, Smalltalk, but still offering more power than what I was used to from C++. Method modifiers and roles, for instance, were things we didn’t have in C++, and I thought they were pretty nifty. I was actually an early adopter of Moose (as you might imagine from my history thus far), but I abandoned it eventually. The problem? Speed.
Moose had an early reputation for being slow. Is the reputation deserved? Well, back then I believe it was. It was slow to run, and very slow to start up. I liked writing in it—to a point—but I disliked waiting for it.
The story today is vastly different. Anyone who tells you today that Moose is still too slow is trying to use Perl like it was C. Believe it or not, there was a time (that I can recall, even) when people accused C of being slow. Not like Assembly, they would say: now, Assembly ... that’s fast! Well, sure, you’re always going to give up some speed for greater expressiveness. But I don’t program in C like I was programming in Assembly—and I haven’t programmed in Assembly since I was a teenager, because it’s just painful.1 Likewise, I don’t program in Perl like I was programming in C ... and, likewise, I don’t program in C any more. Just as painful, in its own way. I went to Perl to move beyond that. The more experienced I get, the more abstractly I want to think about a problem. And my language better keep up.
Moving from C++ to Perl was mostly a step up, except for that pesky problem of objects being a pain in the ass. Now here was Moose, aiming to solve even that dilemma. So, was I willing to give up a little speed for that? Hell yeah. Early Moose, though, was forcing me to give up a lot of speed. Modern Moose? Not so much.
The Perl I was writing before isn’t any slower than the Perl I write today using Moose. There was just a lot more of it, because I was trying to do most of what Moose now does for me on my own. Anyone who has been in this business for any length of time will tell you that measuring programmers by how many lines of code they create per day is moronic. You can measure the really good ones by how many lines per day they remove. And Moose helped me remove a metric shit-ton of code.2
So, shorter code, just as fast (or not enough slower that I can actually notice it, anyway), built-in OOP that’s more extensive than C++—what’s not to love? Well, it’s a lesser complaint (although I won’t go so far as to call it a minor one), but it’s always stuck in my craw: the syntax bugs me.
Syntax doesn’t bother a lot of people, or at least they say it doesn’t. And I believe many of them. But I’m pickier about syntax. The problem I have with Moose (sans extensions) is what I call “cognitive rewriting.”3 Let me try to explain what I mean here.
Here’s the first line of a C++ derived class:
When I read this line, I say to myself, “okay, what follows is going to be a class called Foo, which
class Foo : public Bar
isaBar; got it.” Seems simple enough.
Now, here’s the first line of the Perl-with-Moose equivalent:
When I read this line, I say to myself, “okay, what follows is going to be a package—which is nothing more than a namespace, really. Got it.” Then, sometime later (hopefully not too much later):
“Okay, no, it’s not a package (except in the sense that all classes in Perl are really just packages); it’s a Moose class, called Foo. Let me rearrange my expectations a bit.” Then, a bit later:
“Okay, so it’s still a Moose class, but not a base class: it’s class called Foo which
isaBar. Yep, okay, rearranging ... got it.” This is something you learn to do if you program in Moose. Hopefully those three lines are fairly close together, and hopefully there isn’t much of anything else distracting between them ... although it gets worse with roles, because you quite often have to put your
withafter your attributes, otherwise it doesn’t work properly. That’s some serious lag before you start to get a complete picture of what you’re reading. But often it’s not that bad, and you just get used to it.
You got to used to having function parameters coming in via a bizarro var called
@_ too. But that doesn’t make it any less weird.
That isn’t my only problem with Moose, of course. How about these two lines, found at the bottom of nearly every Moose class?4
Those are what I generally refer to as “the magical Moose incantations.” And you better make sure you put those in your code, because if you don’t ... your code will still work. For now. Maybe forever. Or maybe not. Oh, and also it will be very slow, sometimes. Which you may not notice right away. Or you might.
no Moose; __PACKAGE__->meta->make_immutable;
Aren’t computers supposed to get rid of repetitive boilerplate for me?
So, is it any wonder that I prefer this?
That’s arguably even better than the C++ style. You can get this most easily from MooseX::Declare, but you can also get it from the p5-mop, or from Perl 6 (or, as Joel reminded me in the comments, Moops). But I’ve chosen MooseX::Declare as being the most production-ready method of getting the syntax I want.
class Foo extends Bar
Oh, people try to talk me out of it all the time. They tell me it’s slow, and buggy, but it isn’t, as long as you replace MooseX::Method::Signatures with Method::Signatures. They tell me that MooseX::Declare uses Devel::Declare, which mst says is a big bag of crack, and he wrote the damn thing. To which I respond: a) every piece of code mst ever wrote (that I’ve seen) is a big bag of crack, but that doesn’t change the fact that it’s all dead brilliant,5 and b) just because mst doesn’t like something doesn’t mean I can’t use it, authorship notwithstanding. They tell me that it isn’t Perly, that it’s trying to turn Perl into something like C++. To which I reply ...
That’s what I want.
Well, obviously I don’t want Perl to turn completely into C++, otherwise I could’ve just stuck with C++ in the first place. But I switched to Perl because of it’s ability to Get Shit Done, which is like crack for programmers. But there was this one area where C++ was allowing me to Get Shit Done and Perl was failing me: objects. Now I can have that in Perl, but even better, and with more functionality. So am I willing to suffer a little bit to get it?6 Damn skippy.
Because the legibility of my code is very important to me. Next week we’ll see if we can’t figure out exactly why.
2 A metric shit-ton is, of course, a tiny bit larger than an imperial shit-ton, which makes it even better for silly exaggerations.
3 I say, “I call it” that because I never heard anyone else use that term. Although Google tells me that other people have used the term, so perhaps it was stored it in my subconscious somewhere. In any event, I suppose I’d best not try to take credit for inventing it.
4 Or sometimes you’ll have
use namespace::autoclean up at the top instead of that first line at the bottom. But that doesn’t detract from my point any.
5 In fact, many of my favorite CPAN authors, such as Ingy and the Damian, have this tendency. I think it’s one of the characteristics of genius, personally.
6 And, honestly, I’m not suffering that much. In my experience, the problems of Devel::Declare are overrated. But I suspect we’ll touch on that later in this series.