-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 =pod Normally I save up blog posts and consolidate them into long ones, but apparently we get to see C cross-dress if I blog once a week. So this post will be less content-rich than usual, but it's for a good cause. Anyway, I started writing a new application tonight called L. The details of what PleasureChicken does is an article for another day, but basically, any entity in PleasureChicken can have tags. Implementing this is relatively uninteresting. The entity that can have tags does a role called WithTags, and when a tag is applied to an entity, the entity stores a reference to the tag, and the tag stores a reference to the entity. (This in-memory schema is made persistent with L, BTW.) The interesting part is what the code looks like, thanks to C, C, and C. C is now I way to do types in Moose. The old way to do types was to define types when you used them, and hope you came up with a unique name, since type names were global. (Some people came up with clever ways to add namespaces to this system, and even documented them in the Moose manual as the official way, but nobody actually did this reliably enough to depend on.) Any system that involves hoping for the best is generally a bad thing, and breaks really quickly. The new way, which fixes all the problems with the previous system, is C. It lets you define one or more type library modules and then import those types into modules that need them. In PleasureChicken, we use the same common types throughout our database schema, so I created a type library called C. To create a type library, we start by declaring the types in the library: lang:Perl package PleasureChicken::Schema::Types; use strict; use warnings; use MooseX::Types -declare => [ qw{ Taggable Tag Set }]; That declares C, C, and C. The rest of the module is just defining those types, with MX::Types' new sugar: use MooseX::Types::Moose qw(Object); subtype Taggable, as Object, where { $_->does('PleasureChicken::Schema::Role::WithTags'); }; class_type Tag, { class => 'PleasureChicken::Schema::Tag'}; role_type Set, { role => 'KiokuDB::Set' }; The big thing to notice here is that types are symbols now, not strings. With the types declared, we can C, and have the type symbols anywhere else in the program. C is used to export the symbols, so you have the option of renaming them when importing two type libraries that export conflicting type names. Clean! Define types once, use them anywhere and everywhere, and no more single-quotes around type names. Excellent. So now onto the fun code, the Tag class. This is the full module: use MooseX::Declare; class PleasureChicken::Schema::Tag { use PleasureChicken::Schema::Types qw(Taggable Set); use MooseX::Types::Moose qw(ArrayRef Str); use KiokuDB::Util qw(set); use MooseX::MultiMethods; has 'name' => ( is => 'ro', isa => Str, required => 1, ); has 'applied_to_set' => ( is => 'ro', isa => Set, required => 1, default => sub { set() }, handles => { applied_to => 'members', }, ); # XXX: this needs to be a list, not an arrayref multi method apply_to(ArrayRef[Taggable] $things){ $self->apply_to($_) for @$things; } multi method apply_to(Taggable $thingie){ $self->applied_to_set->insert($thingie); $thingie->tag_set->insert($self); } } 1; There is a lot of fun stuff going on here. We use C, which gives us the "class" keyword (and lots of other things, like a free call to "make_immutable" and "namespace::clean" inside the class definition, saving some boilerplate). We also import our type library, specifying the types we need in this class, Set and Taggable. We use the Set type (and Str type) to typecheck our attributes. (I know it's boring to talk about plain Moose, but even plain Moose gives us cool features. In addition to type checking, which eliminates I of bugs, it also writes code for us. Thanks to C, C<< $tag->applied_to >> is the same as C<< $tag->applied_to_set->members >>. It wouldn't be I to write this method, but it's nice to not need to.) The really cool part, though, is C. It gives us the C keyword that lets us declare a method that runs different code depending on the types of its arguments, just like C does in CLOS. As you'd expect, MX::MultiMethods and MX::Types integrate, allowing us to specialize methods to arguments of the types we define in type libraries and have imported. We take advantage of that to make sure that this Tag is only applied to entities that are Taggable. MX::Types gives us the ability to create new types easily, and in this case, we create C on the fly. (Note the lack of quotes there; it is legal and correct to write type names, even complex ones, without quotes -- types are types now, not strings!) Anyway, I thought this was neat because it's a concise overview of modern Perl's features. There's a type system. Classes are defined with a "class" keyword. We have multimethods. Functions, methods, and multimethods take named, typed arguments. There is no more C. There is no boilerplate like C<< use namespace::clean -except => 'meta' >>. Everything you type in is stuff that actually defines the behavior of I application. There is no more meaningless noise that's just for the compiler. I know I'm preaching to the choir and that I say this all the time... but Perl is really awesome, and has functionality that just doesn't exist in other languages. I think that's cool. So try this stuff in your app now -- you can use any of these features without the others, and you don't have to convert all your classes at once. Just start using MX::Declare (or MX::Types, or MX::MM) for the new stuff, and rewrite the old stuff when you are really bored some time. Perl++! -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (GNU/Linux) iEYEARECAAYFAkn0FNUACgkQ2rw+dVvzZm3igACfTaiYvUpI30p3o+YyryA6Ugrx O+QAoJKLDhGwHG0tPxAz3SWS4dHNGS8D =iEso -----END PGP SIGNATURE-----