Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:
Dear Monks,
How do you create a class variable/class attribute (a la Ruby's @ and @@ in class level[1]) in Moose?
Currently I'm doing this manually via a sub:
package Person;
use Moose;
sub maximum_age { 99; }
[1] http://www.railstips.org/2006/11/18/class-and-instance-variables-in-ruby
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Class variables in Moose?
by stvn (Monsignor) on Jun 05, 2008 at 17:30 UTC | |
Take a look at the MooseX::ClassAttribute module on CPAN for support for class level attributes.
-stvn
| [reply] |
by Arunbear (Prior) on Jun 05, 2008 at 19:59 UTC | |
| [reply] |
by stvn (Monsignor) on Jun 06, 2008 at 01:31 UTC | |
Why does the Moose core not support class attributes? Well, two reasons really. To start with I don't like class attributes, IMO they are a broken concept. Practical ... sure, useful ... sometimes, but this does not make them any less broken. In a pure object model (which Moose strives to be, but can never attain in a p5 compatible world), there is no distinction between a class and an instance, because a class is just an instance of the class MetaClass. The knee-jerk approach is to make class attributes into the instance attributes of the given instance of MetaClass. But this is broken because you can't have several instances of MetaClass each with a different set of attributes (each class is going to want to define it's own class attributes right?) You wouldn't have several instances of your Foo class, each with a different set of attributes in it, right. Which brings me to the the second reason ...TIMTOWTDI. Different people use class level data and methods in different ways, here are some of the different ways I have pondered going about solving this. One way is to subclass each MetaClass such that you have a parallel hierarchy (Foo isa Bar, Foo::MetaClass isa Bar::MetaClass, etc etc), this means your classes inherit class attributes in a predictable way. But this only works with single inheritance languages and pretty much fails miserably the moment you introduce multiple inheritance because it produces an explosion of metaclass combinations, so obviously this is not an option for Moose. Another way is to do what MooseX::ClassAttribute does and create a parallel hierarchy separate from the MetaClass hierarchy, that contains the class data. This neatly sidesteps the issues of MI, by using has-a instead of is-a. I suspect, though I have no proof, that this would prove to break on some deep edge cases if pushed too far, but for the most part it Just Works so this is the one I suggest. Still another way is to use the inside-out-ish technique and store your data in a package scoped variable and simply write your own methods to deal with accessing it, etc. This is more manual and means no Moose helpers, but it gives you the choice of how you want to deal with inheritance of your class data (if you want to deal with inheritance at all). This is typically how I do class level data/method when I do them. Since that is not terribly often, I don't mind going "old school" with it. Another way is to consider class level data "out of band" data, and use a module like MooseX::MetaDescription to add "metadescriptions" to your class's MetaClass. This is how languages like Ruby do class attributes/methods, by having slots in the metaclass specifically for class attributes/methods. I always though that was ugly though (IMO of course, the ruby fanboys would surely disagree). And the last approach, which is a little wasteful, is to simply store that class level data as instance data that it not editable on a per-instance basis. You can do this with Moose like so: The data is not shared per-class though, so if you were to store something more complex like a HASH or ARRAY and to manipulate it directly (push @{$foo->bar} => 100; etc) then it would cease to be class level data. However if you treat it as purely static, this works just fine. You can even override it in a subclasses like so: Of course this is not ideal in many cases, but it is just OWTDI. So, basically, the short answer is: I couldn't decide which way was the right way, so I left it open to MooseX:: extensions to solve the problem.
-stvn
| [reply] [d/l] [select] |
|
Re: Class variables in Moose?
by jds17 (Pilgrim) on Jun 05, 2008 at 08:22 UTC | |
test.pl Person.pm Types.pm I like to separate the type constraints in a separate module Types.pm. What I just told you is no news, of course, you can find very good introductions on the Moose homepage, the first aricles I read and which should give you a good start are the ones cited there by Randal L. Schwartz: http://www.stonehenge.com/merlyn/LinuxMag/col94.html and http://www.stonehenge.com/merlyn/LinuxMag/col95.html | [reply] [d/l] [select] |
by skirnir (Monk) on Jun 05, 2008 at 08:33 UTC | |
I don't know if there's a different way in Moose to do that, but How do I create static class variables (class data)? may be what the OP is looking for. | [reply] [d/l] |
by jds17 (Pilgrim) on Jun 05, 2008 at 10:11 UTC | |
| [reply] |
by skirnir (Monk) on Jun 05, 2008 at 10:31 UTC | |
|
Re: Class variables in Moose?
by j1n3l0 (Friar) on Jun 05, 2008 at 18:04 UTC | |
UPDATE: Just seen stvn's post ... do that instead =) UPDATE: To do this with stvn's recommendation, this example would look like so: Don't know why the commented line #MooseX::ClassAttribute::containing_class()->meta()->make_immutable(); does not quite work. Its an open ticket on the RT queue =) Smoothie, smoothie, hundre prosent naturlig! | [reply] [d/l] [select] |