Dear monks,
I'd like to ask you for an advice regarding attribute accessors' naming.
I started to develop a project that is supposed to have quite a ramified hierarchy of classes, for example, the `SomeFramework` class, a bunch of classes like `SomeFramework::Logger` and, let's say, classes similar to `SomeFramework::SomeSubsystem::SomeComponent::SomeAPI` classes.
My goal is to design the most efficient communication between all these classes. I'll explain how I'm doing it now, so maybe you would like to share some opinions on how to make it better.
When I initialize the `SomeFramework` class, I have an object reference which I use from my application.
my $someframework = SomeFramework->new(parameter => 'value');
The `SomeFramework` class has some attributes, such as `logger`, `configuration`, etc, here are some examples of their definitions:
has 'logger' => ( is => 'ro', isa => 'SomeFramework::Logger', reader => 'get_logger', writer => '_set_logger', builder => '_build_logger', lazy => 1 ); sub _build_logger { my $self = shift; SomeFramework::Logger->new(someframework => $self); }
I'm passing the reference to the parent object to the child object, because I need the child to have access to the parent and its methods & accessors. So in the `SomeFramework::Logger` I have such attribute:
has 'someframework' => ( is => 'ro', isa => 'SomeFramework', reader => 'get_someframework', writer => '_set_someframework', required => 1 );
It lets me to have access to any object from within the `SomeFramework::Logger` class, usually it looks something like that:
my $configuration = $self-> get_someframework-> get_configuration-> get_blah_blah;
To extrapolate it, let's look into the `SomeFramework::SomeSubsystem::SomeComponent::SomeAPI` class. This class has its own "parent" attribute (let's call it `somecomponent`) which is supposed to have a reference to a `SomeFramework::SomeSubsystem::SomeComponent` object as the value. The `SomeFramework::SomeSubsystem::SomeComponent` class has the attribute for its own parent attribute (we can call it `somesubsystem`) which is supposed to contain a reference to a `SomeFramework::SomeSubsystem` object. And, finally, this class has the attribute for its own parent too (`someframework`), so it contains the reference to a `SomeFramework` object.
It all makes it possible to have something like that inside of the `SomeFramework::SomeSubsystem::SomeComponent::SomeAPI` class:
my $configuration = $self-> get_someframework-> get_somesubsystem-> get_somecomponent-> get_configuration-> get_blah_blah;
The first thing I'd like to know: is it a good practice? I hope, it is, but maybe you would advice me to go some more smooth way?
The second question is a bit more complicated (as for me), but I hope you'll help me with it. :) I like canonical names of accessors recommended by D.Conway in his "Perl Best Practices", but I'd like to do something like that:
my $configuration = $self->sc->ss->sf->conf->blah_blah;
Surely I can name all readers in this laconical manner:
has 'some_framework' => ( is => 'ro', isa => 'SomeFramework', reader => 'sf', writer => '_set_someframework', required => 1 );
But I don't like the idea of managing without the "standard" accessors names. :(
Also I can use `MooseX::Aliases`, it works fine for something like that:
has 'some_framework' => ( is => 'ro', isa => 'SomeFramework', reader => 'get_someframework', writer => '_set_someframework', required => 1, alias => 'sf' );
It looks fine, but there's an issue with attributes which names do NOT needed to be shortened. For example:
has 'api' => ( is => 'ro', isa => 'SomeFramework::API', reader => '_get_api', writer => '_set_api', required => 1, alias => 'api' );
In this case Moose throws an exception: `Conflicting init_args: (api, api) at constructor`. :( As I understand, MooseX::Aliases tries to create an attribute with the same value of the `init_args` parameter, so it fails. By the way, sometimes it happens, but sometimes it works fine, I haven't discovered when exactly it doesn't work.
Maybe I should have something like that:
? But it doesn't seem to be the best option too, because it helps me only if the attribute contains a reference some object for which I can define the `return_self` method. If the attribute contains a reference to some "foreign" object or some other value (e.g., a hash), it won't be possible to call that method. :(has 'api' => ( is => 'ro', isa => 'SomeFramework::API', reader => '_get_api', writer => '_set_api', required => 1, handles => { api => 'return_self' # ^^^ It's supposed to have some method that # returns the reference to its own object } );
Ugh... Sorry for such a long rant! I hope, you have managed to read to here. :)
I'll be very happy to get to know what do you thing and what would you suggest to do. Feel free to share any your ideas on this topic, any fresh ideas will be very appreciated!
In reply to Names of attribute accessors (Moose) by v_melnik
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |