2009-04-24

The New Moose Warning and the New Moose Critic

Role Design

A role is something that classes do. Usually, a role encapsulates some piece of behavior or state that can be shared between classes. It is important to understand that roles are not classes. You cannot inherit from a role, and a role cannot be instantiated. We sometimes say that roles are consumed, either by classes or other roles.

A role can be composed into a class. In practical terms, this means that all of the methods and attributes defined in a role are added directly to (we sometimes say "flattened into") the class that consumes the role. These attributes and methods then appear as if they were defined in the class itself. A subclass of the consuming class will inherit all of these methods and attributes.

– Dave Rolsky in Moose::Manual::Roles

Roles can be composed to create new roles. This is not like inheritance; this operation is actually commutative summation. This does not establish a hierarchy, instead it creates a composite role with the methods, attributes, requirements, etc. of its component roles. If two or more roles in the composition provide different methods with the same name, a conflict is generated. Such conflicts do not immediately issue fatal errors, but they must be resolved at composition time. One of the ways a role consumer can resolve such a conflict is by providing its own implementation of the conflicted method name. The method could do whatever the programmer sees fit, but it is most sensible for this custom implementation to invoke the conflicting methods from the component roles.

For example, consider two roles that provide a validate method. A class can consume the summation of these two roles. Since the two component roles each attempted to contribute a validate method, validate is a conflicted method in the composite role. To resolve this conflict, a consuming class must define its own validate method. The class's validate method should generally call the validate method of both roles. However, the class needs some way to disambiguate the two roles' validate methods so that it can call each in turn. For this reason, roles support method aliasing. The consumer can alias each role's validate methods. Aliasing only adds a new name for a method; it does not change the name of any method. That means the original validate methods are still conflicting. The consuming class can provide a validate method to resolve this conflict, whose implementation calls each role's aliased validate.

# this "with" sums the two roles then applies one role to the class
with (
    'Role::Foo' => { alias => { validate => 'validate_foo' } },
    'Role::Bar' => { alias => { validate => 'validate_bar' } },
);

sub validate {
    my $self = shift;
    $self->validate_foo(@_);
    $self->validate_bar(@_);
}

While this may seem like a lot of effort, role design has very nice theoretical and practical properties. Unlike multiple inheritance and mixins, roles issue an error when there is an unresolved naming conflict. The programmer has good tools for resolving conflicts: method aliasing, method exclusion, and method overriding. In our above example, the consuming class could have excluded the validate method from one of the two roles so that there would be no conflict (since only one role is providing a method with that name). Finally, the consuming class could have overridden the conflicted validate method. The overriding implementation may not need to call the component roles' validate methods, perhaps obviating the need for aliasing. The example above used a combination of aliasing and overriding. All of these features are available even when there are no method conflicts, granting additional flexibility to roles.

The New Moose Warning

Ovid has written eleven articles on roles since March 4th (as of this posting). Most of them have praised roles and explained his happiness with how comprehensible his large class role space has become. However, in Not All Features Are Useful (Moose Roles), Ovid describes his frustration at spending a long time trying to discover an unintentional use of the method overriding feature. Which is silent.

Marcus Ramberg was the first to suggest the addition a warning to the Moose core when a class overrides a method from a role it consumes. This way we could push the "frontier" of the beloved collision detection a little further, into boundary between roles and classes. The warning (which was uncannily easy to implement, as if it had existed in a past Alces) would read like:

The Quux class has implicitly overridden the method (validate) from role Role::Foo. If this is intentional, please exclude the method from composition to silence this warning (see Moose::Cookbook::Roles::Recipe2)

I was one of the very few vocal proponents of this new warning. Suggesting to users that they explicitly list which methods they intended to exclude from composition would benefit maintainability. Other developers would not have to guess whether each method override was intentional or not; intention would be evident from the exclusions, or lack thereof. In a large, evolving system, accidental name collisions are bound to happen. I'd much prefer a compile-time warning over spending even ten minutes debugging why my application decided to start connecting to a database named "Shawn Moore".

However, many people were unhappy with this warning, because it complained about perfectly valid semantics. Classes overriding local role methods has been in the design of roles since they were conceived as traits by Smalltalk researchers. Due to limitations in Perl's builtin warning system, the warning was also difficult to disable for a particular scope.

chromatic in particular decried this new warning in his article The Value of a Warning. While I continue to disagree with a few of his specific points, the argument he made in a comment on Ovid's Well, Now I Know (Roles) article struck a chord.

The moment you throw a mandatory default warning on two of the four appropriate and specified uses of roles, you've penalized them. You're subtly encouraging people not to use the most important and most powerful features of roles! You're actively discouraging people from taking advantage of allomorphism using well-established and long-recommended design techniques explicitly made safer and more understandable by roles.

He's absolutely correct. Even subtly discouraging users from perfectly good designs is unacceptable. I reverted the warning.

The New Moose Critic

One of the suggested ideas was to leave the warning disabled by default. For a while I thought it was quite ridiculous to turn Perl's own warnings on in your class, but leave Moose's own warnings off. After all, we have grown as a community to love use warnings; it would be silly to repeat that default-off mistake.

The final section of chromatic's The Value of a Warning held the best compromise. I was dead set against warnings that were off by default, so I didn't give the ideas the thorough consideration they deserved.

Compare that to optional Perl::Critic warnings. If your project decides that a method length of more than 24 lines is a code smell, you can determine that yourself. If you decide that a specified, implemented, and tested feature of Perl 5 is troublesome (tie), you can disallow it yourself locally.

What we need is a set of Perl::Critic policies for Moose. Elliot Shank has already started a Perl-Critic-Moose for, among other things, ensuring (statically) that you make your classes immutable.

Moose stores plenty of data in its metaobjects, rich for plunder. Though nearly all of Perl-Critic performs static analysis, there is precedent for dynamic Perl-Critic policies. We could stand on the shoulders of the Perl::Critic giants so as to reuse and contribute to their configuration system, testing modules, and great community.

Some easily-implemented dynamic Moose policies (of varying severity) could highlight:

  • Classes overriding methods from locally consumed roles
  • Classes overriding methods from their superclasses without using method modifiers (including the override modifier)
  • Declaring builder methods without leading underscores
  • Leaving classes mutable
  • Declaring new methods instead of using the many object construction hooks

I think this is an excellent compromise and I can't wait to begin implementing Moose policies.

200 IRC messages about darcs

I have taken two logs from Perl's Moose IRC channels and plucked out 200 lines that say something about darcs. I have done my best at anonymizing the speakers.

I have chosen to present the lines ordered first by author, then by time. What I find saddest is that there are very few users — in fact, zero, in this sample — really adopting darcs. Some of the few darcs users migrate to git during the course of the log (which is why I chose this author-major format). I'm posting this to maybe shed some light on why git is winning, and demonstrate some actual negative perceptions that darcs has.

The logs span from August 2007 to today, so some of the details are out of date. Some of the details have never been in date. Perception is sadly more telling and damning than the actual facts anyway.

If you'd like more context or a timestamp for a particular line, just leave a comment.

<$A> unless you're a darcs weenie it's probably for the best
<$A> And yes I have patched code for $K so I have used darcs :)
<$A> Well and I'm saying darcs isn't gonna be a solution for that group
either.
<$A> while installing darcs has always been ... interesting
<$A> darcs--
<$A> $S: as darcs was the only thing I actively used that required GHC...
<$A> $E: well that would be darcshub
<$A> since I dont' even ahve darcs installed on this laptop

<$B> I already have svk, darcs and git
<$B> $E: how does it talk to darcs?
<$B> I don't believe darcs makes write over HTTP easy

<$C> darcs is a very good example on a system that has made this simple.
<$C> $G: Also, darcs can be a real pita to get running on some
systems thanks to haskell.
<$C> $I: Well, darcs isn't bad, but it has too many drawbacks for me.
<$C> Portable is not the word I'd use to describe darcs.
<$C> $J: How is branching with darcs-git in terms of performance? I
remember one of my issues back when I tried darcs was that branching was a
very expensive operation, has this changed with darcs-git?
<$C> In general, performance has not been a primary consideration when
developing darcs.
<$C> darcs would be better if it didn't require haskell and weren't so
damn slow on certain workloads.
<$C> $E: When it comes to cherrypicking, darcs will by design by
superior to pretty much every other scm. But git does a well enough job that
it's not a strong argument for changing.

<$D> $C: never used darcs, thanks for pointing it out
<$D> anyone have any opinions on darcs?
<$D> holy mother of darcs.

<$E> I *heart* darcs
<$E> I'd like darcs to be scalable
* $E *hearts* darcs. ah the pleasure and the pain
<$E> it has it's own darcs branch that it works on. I haven't set up a
cronjob to pull from the main repo yet
<$E> $K, your darcs rss feed continues to drive me crazy with its lack
of project-name in the feed item info
<$E> darcs++
<$E> Though git seems to be eating darcs. I learned git cherrypicking
(git ci --interactive) the other day and it isn't quite as easy as darcs but
damn close
<$E> just darcs get will be fine. web browser is fine too :)
<$E> $G, I do have _darcs/prefs/author
<$E> darcs++
<$E> what's up with this whole git needing some sort of special server?
I can't just drop it into an HTTP dir like with darcs?
<$E> darcs darcs darcs darcs
<$E> good! then I don't have to do anything, which is what I like about
darcs. Since my entire projects directory is out there, that is.
<$E> actually I love the concept of github. I just wish they also
supported darcs :)

<$F> darcs doesn't save enough information
<$F> darcs uses stupid terms like "patch calculus"
<$F> I just noted that darcs-git was on my TODO list
<$F> $K: are you using a different darcs-git ?
<$F> I can't see any git related changes in darcs' history for aeons,
since 2006
<$F> in the darcs code base I also saw "Hopefully"
<$F> darcs is essentially guessing these for you as it goes
<$F> was that "darcs supremacy" ?
<$F> yeah.  darcs can get away with things like that because it doesn't
really record the history, it just has a pile of patches

<$G> darcs doesn't manage permissions or bits at all. it can be very
annoying in multideveloper projects
<$G> branching in darcs? er.. cp -r
<$G> though darcs put *might* use symlinks
<$G> $K: cool! one of the nicest things about darcs, yes :)
* $G wants the relative simplicity of darcs back
<$G> darcs makes branching and killing branches just as easy..
<$G> anyway, darcs optimize --relink --sibling DIR
<$G> git commit --interface and darcs record aren't cherrypicking.
they're interactive commit. cherrypicking is the same principal applied to
push/pull
<$G> I bet he meant commit.. darcs users call them patches :)
<$G> (darcs tag)++
<$G> $E: sent you some darcs patches :)
<$G> $E: if you have a _darcs/prefs/author file with your email address
in your serverside <project> repo, I won't have to paste in your addy
<$G> $E: okay, maybe it's just darcs being dumb. or me. :)
<$G> it's just that darcs is my weapon of choice
<$G> if you're using git/darcs/hg/bzr/etc I'm happy. if you're using svn
I'm twitchy
<$G> darcs beats bzr by two years or so
<$G> darcs just didn't make it easy to get at em
<$G> darcs supremacy
<$G> darcs isn't that slow :P
<$G> I'm very happy with darcs. I don't need to sell you guys on it.
you're already in love with git. which is fine, because it's not svn. yay. :)
<$G> I have aliases for commands like "darcs record"
<$G> I would genuinely like to see a "here's why git is better than
darcs"
<$G> $K: do you use git commit or is there a good darcs-style facade (at
least for committing)?
<$G> $package_manager install (git|darcs)
<$G> darcs has an amazing interface and the features to back it up, so
that's why I still use and love it even though it and everything not-git lost
in big ways
<$G> $O: I'm still very happy with darcs
<$G> $K: what do you use to convert darcs repos to git?
<$G> better than darcs
<$G> $N: use darcs for like a day
<$G> darcs' interface is much better designed than git's
<$G> when I want to revert changes in darcs I can type "darcs revert"
and it'll go through all the unstaged hunks and prompt if I want to revert
them
<$G> if you write me a <patch> I'll wrangle darcs
<$G> I'm still too used to darcs where every branch is a repo :)
<$G> in darcs (I know you know $F, but for others) it just doesn't
prompt for patches you've already pulled, or for patches which depend on
patches you haven't pulled
* $G likes darcs' tags.. just an empty commit but useful for associating a
message with a set of patches
<$G> I like darcs's simpler branch model better.. every checkout is a
branch
<$G> (bashes darcs, but it does explain why I dislike git's merge
history :)
<$G> probably easier just to install the optional modules because darcs
<$G> still no darcs though
<$G> nope, it's in darcs!

<$H> And darcs lives in another universe. :-)

<$I> is finally using git for a project but finds darcs more intuitive
to use
<$I> $C: I love that the darcs client is a single binary that fits on my
flash drive with no dependencies

<$J> you may yet convert me back from darcs to use svk fulltime! ;)
<$J> well, darcs-git, really.
<$J> (native git repos support is part of darcs trunk.)
<$J> well, I havn't used darcs on huge trees, so I can't really answer
that question
<$J> darcs amend-record is a good way to work with
lightweight-local-pseudo-branch though.

<$K> use darcs =)
<$K> $F: no, darcs-{un,}stable
<$K> my darcs has no git support
<$K> i'm using darcs-to-git
<$K> svk ci --interactive still sucks compared to darcs
<$K> well, the darcs approach works a little more like two ordered sets
<$K> it's a darcsweb issue, not a darcs one
<$K> ~/.darcs/prefs will get apply --post "chmod -R a+r _darcs"
--run-posthook
<$K> hey, it's even in the manual, as an example:
http://darcs.net/manual/node5.html#SECTION00510010000000000000
<$K> http://www.sanityinc.com/tags/darcs-git
<$K> and also git can support darcs' dependency graph
<$K> or if you can build a darcs-git
<$K> or darcs... mmm... darcs
<$K> he always says "darcs bad, git good" regardless of context
<$K> or use darcs =)
<$K> i see two darcs patches from you in my inbox, the last one being
the add download link for darcsweb
<$K> i'm trying to darcs get =)
<$K> no, darcs is the "we do the math of patches better than anyone"
project right? or pure joy or a version control system written in haskell or
http://darcs.net or http://darcs.net/DarcsWiki/CategoryBinaries for download
or fantastic, but everything you can do in darcs you can do in git...
<$K> until you use darcs
<$K> if you aren't a darcs fan you can use the download link
<$K> it's just not very self documenting like e.g. darcs
* $K learnt svk and darcs from just their help commands
<$K> the darcsweb interface is much better
<$K> i wanted darcs is <reply> DARCS DARCS DARCS DARCS DARCS ....
<$K> no, use darcs!
<$K> one of the things I like about darcs is that you can change history
to pretend you weren't stupid =)
<$K> darcs' is lovely though
* $K uses darcs for <widely-used-project>
<$K> $G:
http://lists.osuosl.org/pipermail/darcs-users/2008-March/011695.html
<$K> darcs UI to a git checkout of a subversion repo
<$K> http://wiki.darcs.net/DarcsWiki/Workflows
<$K>
http://blog.worldmaker.net/2008/aug/10/darcs-workflow-completely-distributed-pull-only-wo/
<$K> darcs is actually even more immutable
<$K> in darcs a resolution is it's own new commit
<$K> you can download a tarball from my darcs
* $K has been considering switching his projects from darcs simply because
it's more popular
<$K> the bottom line is that more people can contribute with git than
with darcs when they want to patch something
<$K> $M: with darcs you just need webspace
<$K> darcs put foo:.htdocs/blah
<$K> that gives me most of the darcs goodness
<$K> also git cherry-pick is pretty much darcs pull
<$K> i'm used enough to git now that I can just let darcs go
<$K> it ain't gonna happen (the darcs revolution)
<$K> for me anyway, after i've been using git all day going to darcs is
confusing
<$K> and darcs is missing a few features git has
<$K> $A: darcs got me hooked on those initially, but git allows a lot
more
<$K> darcs is good, but not as streamlined as git in that respect
<$K> darcs is unordered by default
<$K> which is a little more powerful than darcs in some ways
* $K needed to convert from darcs so it was a bigger step mentally i guess
<$K> git-darcs-import++
<$K> $U: to skip a silly initial commit created by git darcs-import
<$K> $O: $G is the "other" guy using darcs
<$K> he's actually the one who got me using darcs
<$K> $E: it's not darcs, but you can pretend
* $K is pretty content with the move to gits. 2 months ago i still felt bad
about thinking about it, but i realized that even though darcs is much
better in terms of social features i benefitted from it like... twice
<$K> kinda like the ssh + darcs + sudo trick
<$K> $E: the problem with darcs is that nobody is developing crap for it
<$K> mercurial has an order of magnitude more users than darcs
<$K> darcs is where all this shit was invented

<$L> oh and a little darcs.  looking at going to git now tho

<$M> it's definitely not in darcs
<$M> oh, well, I mean, darcs bad git godo
<$M> darcs bad, git good
<$M> it's better than darcs, which is bad
<$M> no, I meant hardly darcs supremacy
* $M has no objection to anyone loving darcs, either
<$M> $K: I just meant "see, you COULD do it with darcs"
<$M> $N: he feels more like he's using darcs

<$N> yes, only communists use darcs
<$N> I found darcs not much more comprehensible, iirc.
<$N> darcs is neat
<$N> darcs is very nice
<$N> but if you love darcs, you're a loser
<$N> http://blog.moertel.com/articles/2007/12/10/how-i-stopped-missing-darcs-and-started-loving-git
<$N> so is there a dist.darcshub.com?
<$N> $V: he wanted you to use his clisp port of darcs
<$N> darcshub
<$N> $G: did you get a question to the darcs thing you were tweeting
about?

<$O> darcs is good, but missing features
<$O> it would be nice to be able to switch between git's ordered commits
to darcs' "if it applies..." model
<$O> apt-get install darcs # done
<$O> the exponential-time merge issue is a problem, but fixed in darcs2
AFAICT
<$O> i don't use darcs, just saying it's the only other VCS that's not
poorly designed :)
<$O> i use git, $V uses svn, $A uses svk, and $K uses darcs...
<$O> unfortunately, darcs and hg both cut-n-pasted gitweb into
darcsweb/hgweb
<$O> abstract away darcs/git/svn and just give it an id
<$O> darcs and git are a pain if you want to add committers like with
svn
<$O> i think i am switching to darcs [editor: this was irony]
<$O> yeah, darcs is Not Yet Dead
<$O> unfortunately for darcs, git has the ruby fanboi contingent behind
it

<$P> eeek darcs!
<$P> that's darcs get --partial  is it?

<$Q> darcs corrupts its database and *crashes* with segvs.  I thought
Functional Languages weren't supposed to fuck up pointers.  what is that?

<$R> $K: I only just learnt that darcs is written in Haskell.  That
makes it extra cool.
<$R> $K: Although to be honest, I'd probably just use darcs2git (I'm
sure there's one out there) so I don't need to learn yet another source
control system.
<$R> I've not tried darcs yet.  I fell into git because p5 was (and
still is) talking about moving to it, so I figured I should take a look.  It's
actually been the only distributed vcs I've used.

<$S> I like git because it's insanely fast (I prefer darcs 2, though,
but git is faster)
<$S> I'm a darcs fanboy. ;)
<$S> I used svk for a brief period, but then I used darcs for a longer
period of tim.
<$S> I prefer darcs revert.
<$S> darcs at least doesn't require it at runtime
<$S> I went from svk to darcs.
<$S> that use darcs for cpan stuff?

<$T> $K: why did you need those for the conversion from darcs?
<$T> there are a few tools to improve cherry picking and add -p, making
it more darcs-like
<$T> would you mind writing down the things you don't like about git and
are used to because of darcs?

2009-04-21

hi

I'm getting pretty sick of use.perl.org so I'm moving my blog here. It's also for a clean slate for Matt Trout's Iron Man challenge. My old posts are: