When should I use `use`? - perl

As long as I can remember, whenever I use a module I include a use line at the beginning of my code.
Recently I was writing two Moose object modules that use each other. Look at this over-simplistic example:
One module:
package M1 0.001;
use Moose;
use 5.010;
use namespace::autoclean;
# use M2; ### SEE QUESTION BELOW
has 'name' => (
is => 'ro',
isa => 'Str',
required => 1,
);
has 'very_cool_name' => (
is => 'ro',
lazy => 1,
builder => '_build_very_cool_name',
);
sub _build_very_cool_name {
my ($self) = #_;
my $m2 = M2->new( m1 => $self );
return 'very ' . $m2->cool_name();
}
__PACKAGE__->meta->make_immutable;
1;
Another module:
package M2 0.001;
use Moose;
use 5.010;
use Data::Dumper; # TODO DEBUG REMOVE
use namespace::autoclean;
use M1;
has 'm1' => (
is => 'ro',
isa => 'M1',
required => 1,
);
sub cool_name {
my ($self) = #_;
return 'cool ' . $self->m1->name();
}
__PACKAGE__->meta->make_immutable;
1;
And a short example that uses them:
use strict;
use warnings;
use 5.010;
use M1;
use M2;
my $m1 = M1->new(name => 'dave');
say $m1->very_cool_name();
Now, note the two modules use each other. M1 creates an instance of M2 and use it to generate very_cool_name, while M2 has an instance of M1 as an attribute.
Now, if I uncomment use M2; in M1 my eclipse goes mad. I guess it's because this a the loop created by this 'circular use`.
I commented this use and everything seems to works fine (I think...), but makes me really anxious (I'm using an object without use-ing its class! Is that 'legal'?..). This also which made me wonder:
When do I really need to use use? I think that I was taught to always use it, and surely when I use an object.
Is there anything fundamentally wrong when two modules use each other (in the sense that each uses an object of the other module; I know there some cases where this is logically impossible, but sometimes - as in this case - I think it does make sense).

From a Perl perspective it's fine. use is smart enough to recognize that a module has already been loaded and not load it again. That said, the faint whiff of code smell should make you think about whether mutual dependency is acceptable or if you should refactor your code to eliminate it.
Eclipse, apparently, is not quite as bright. Commenting out one of the use statements to placate the editor will probably work but could create subtle bugs depending on the order the modules are loaded in (by the application) and when they use each others functionality. e.g. if M1 were loaded first, didn't use M2, and had a BEGIN block that needed functionality from M2... boom! If nothing happens until runtime (which is likely) you should be okay.
While it isn't an issue here, you'd also have problems if your use imported symbols from the other package. In that case couldn't remove the use without changing your code to fully qualify all references. (e.g. call MyModule::function() instead of just function())

There's no reason for M2 to use M1. You don't actually have a recursive dependency.
All M2 does is validate some object's classname -- which doesn't require having loaded M1 -- and call a method on it -- which means whoever constructed that object loaded M1.
Your rule about needing to use a class in order to call methods on an object of that class is wrong. use a class when you're going to call methods on the it directly -- for example, new. (This assumes pure OO modules, obviously, not things that export functions/symbols.)
Consider polymorphism. It is a feature that I can make my own subclass of M1 (called, say, M1A) and pass it to M2 without M2 having to know anything about the existence of M1A.

Related

make object instance immutable

I want to be able to instantiate a Moose based object add to it until I serialize it and then I want to make it unchangeable. How can/should I go about doing this?
I would make two classes and a common Role:
package Thing
use Moose::Role;
has some_attrib => (isa => 'AnotherThing');
### Behaviour (the important stuff) goes here
package ImmutableThing;
use Moose;
with 'Thing';
has +some_attrib => (is => 'ro');
sub finalize { shift }
package MutableThing
use Moose;
with 'Thing';
has +some_attrib => (is => 'rw');
sub finalize {
my $self = shift;
Thing->new({some_attrib => $self->some_attrib});
}
I'm not sure that having mutable and immutable forms of the same class is necessarily a good idea though. I tend to try and think about build time and operation time as two distinct phases with different interfaces.
I would be more inclined to write a Parameter Collector (I've capitalised it like it's a pattern, but I've not seen it in the literature) that has an interface optimised to gathering the info needed to create a Thing, and the Thing Itself, which is the object that's used by the rest of the program.
I don't know of (and can't easily find) any modules to do this on CPAN which is surprising but explains why you are asking :-)
A "before" modifier over all your attributes is the obvious way to go about it. I'm sure there's a suitable meta-programming way to get a list of all attribute accessors and apply the modifier, but I'd be tempted to explicitly list them all with a big comment.
Have you considered whether you have one class or two here (Thingy, LockedThingy)? Two classes would let you encapsulate the meta cleverness if you're that way inclined.

Moose (Perl): Is it okay to use %$object to get the data representation of an object for serialization?

I frequently use Moose to make sure my data have suitable default values, like here:
package Bla;
use Moose;
has eins => is => 'ro', isa => 'Int';
has zwei => is => 'ro', isa => 'Int', default => 2;
no Moose; __PACKAGE__->meta->make_immutable;
package main;
use v5.10;
use Data::Dumper;
use URI;
my $bla = Bla->new( eins => 77 );
my $bl2 = Bla->new;
print Dumper $bla, $bl2;
say join "\t", %$bla;
say join "\t", %$bl2;
my $u = URI->new( 'http://www.example.com/ws' );
$u->query_form( %$bla );
say $u;
$u->query_form( %$bl2 );
say $u;
As long as that kind of data container doesn't have any reference members (hence no nesting), would you say it is okay, or recommendable, to just use the object hashtable as in %$object if you want to get at the raw data, let's say as initializer for serialization via URI->query_form or similar methods? Or is there a better way to achieve this that's built into Moose?
UPDATE
Looks like I've been leading people on the wrong tracks by dropping the little word serialization in the lines above, and in the title, and even in the tags. Note that I'm not interested in finding serializers. In my example, the URI module is the serializer. The question is how to get at the data to feed URI->query_form (or any other serializer I might try). So what I want to know is whether for a given Moose object $object it is okay to grab the data (keys and values, or, if you prefer, property names and values) by just dereferencing the object reference, as in %$object? This will work, if my experience hitherto collected is anything to go by, as long as the objects don't contain any reference values (like array references, other objects, etc) and - the thing I'm not sure about - Moose won't use the instance reference to store data of its own, like __MOOSE_WHATNOT => $funky_moose_addon. So might Moose use the instance reference to store some of its own data, or is that precluded by design?
UPDATE 2
To answer the question in the title:
No, it's not okay to use %$object to get at the data of a Moose object, even if it doesn't contain any reference values so you'd get a copy of the strings and numbers that make up the $object. It's not okay because it breaks encapsulation. It might even result in a runtime error because although the hash is the default data structure to form the base of a Moose object, there is no guarantee that it will always be a hash, and it might in fact be something else.
You should use MooseX::Storage instead, which will provide the object with a pack method.
As jira has said the canonical way would be to use MooseX::Storage. The problem with %$object is that while the default storage for a Moose object instance is a blessed hash, Moose makes no formal promises that this is always the case. MooseX::GlobRef, MooseX::NonMoose, MooseX::InsideOut for example all allow for alterative instance structures.
A package like MooseX::Storage uses the MOP to interrogate the instance meta-object and serialize the data structure properly. You can of course do this by hand by crawling the Moose::Meta::Class that is behind every Moose object, but honestly MooseX::Storage is well written and very stable at this point.
The standard usage would be:
package Class {
use Moose;
use MooseX::Storage;
with Storage();
...
}
my $o = Class->new(...)
my $u = URI->new( 'http://www.example.com/ws' );
$u->query_form( $o->pack );
Moose "native" way would be to use MooseX::Storage set of classes.

Can't locate object method via package subclassing DBI

this is my first foray into subclassing with perl and I am wondering why I am getting this simple error...
"Can't locate object method "prepare" via package "WebDB::st" at /home/dblibs/WebDB.pm line 19.". It seems to find the module WebDB ok, but not the prepare subroutine in ::st
First here's my package (both packages are in one file, WebDB.pm)
package WebDB;
use strict;
use DBI;
sub connect {
my $dbh = (DBI->connect ("DBI:mysql:test:127.0.0.1", "root","",
{ PrintError => 1, RaiseError => 0 }));
return bless $dbh, 'WebDB::st';
}
package WebDB::st;
our #ISA = qw(::st);
sub prepare {
my ($self, $str, #args) = #_;
$self->SUPER::prepare("/* userid:$ENV{USER} */ $str", #args);
}
1;
I also tried replacing the "our #ISA = qw(;;st)" with "use base 'WebDB'" and same problem.
I'm thinking it's probably something very simple that I'm overlooking. Many thanks! Jane
Subclassing DBI has to be done just right to work correctly. Read Subclassing the DBI carefully and properly set RootClass (or explicitly call connect on your root class with #ISA set to DBI). Make sure you have WebDB::st subclassing DBI::st and a WebDB::db class subclassing DBI::db (even if there are no methods being overridden). No need to rebless.
Avoid using base; it has some unfortunate behavior that has led to its deprecation, particularly when used with classes that are not in a file of their own.
Either explicitly set #ISA or use the newer parent pragma:
package WebDB;
use parent 'DBI';
...
package WebDB::db;
use parent -norequire => 'DBI::db';
...
package WebDB::st;
use parent -norequire => 'DBI::st';
...
Are WebDB and WebDB::st in one file or two? If they are in separate files, I don't see anything that is doing a use WebDB::st;, which would cause that file to be loaded.
You can do either of these things as a remedy -- put the two packages in the same file (that would look exactly as you have pasted it above), or add a use WebDB::st; line in WebDB.pm.
(I'd also add use strict; use warnings; in both these packages too.)
Also, the prepare function is not in ::st -- there is no such package (unless it is defined elsewhere). prepare is in the WebDB::st namespace -- via the package declaration. You are however declaring that WebDB::st has ::st as a parent.
If subclassing is as tricky as ysth seems to think, I might recommend Class::Delegator from CPAN. I use if for classes that want to act like IO. And by it, Perl is the first language (that I am aware of) that has an expression language for aggregation, delegation, encapsulation almost equal with inheritance.
package WebDB;
use strict;
use DBI;
use Class::Delegator
send => [ qw<connect ...> ]
, to => '{_dbihandle}'
...
;

perl Moose accessor madness - can't define only a reader or writer accessor!

So I'm just trying to do a very simple thing: define a custom reader accessor for a moose attribute. So I try this:
has 'compiled_regex' => (
isa => 'RegexpRef',
is => 'rw',
reader => 'get_compiled',
);
but get_compiled never gets called, presumably because compiled_regex is read/write. Ok, no problem. I next try this:
has 'compiled_regex' => (
isa => 'RegexpRef',
writer => '_compile',
reader => 'get_compiled',
);
and that produces the following error:
Can't locate object method "compiled_regex" via package "PrettyRegex" at ../lib/Pretty/Regexs.pm line 39.
which refers to this line which is in the _compile method:
$self->compiled_regex(qr/$self->regex/);
Now I haven't gotten much sleep in the past 3 days so maybe I'm confused, but it seems that even if this did work, it would create an infinite regress since I've defined the writer as _compile ... so what am I missing here?
tried Sinan answer but still getting:
Can't locate object method "compiled_regex" via package "PrettyRegex" at ../lib/Pretty/Regexs.pm line 41.
I'm unclear on what you're trying to do. reader and writer are methods that Moose creates for you, not methods that you write and it calls.
I think you need to restate your question to explain the higher-level problem that you're trying to solve. I expect there's a better way to do it than you've currently thought of, but we can't be sure without knowing what you're really trying to do.
If you're trying to get your custom method called when the attribute is read, just name the reader something else (like _get_compiled_regex), and name your method compiled_regex. Or use a method modifier on the reader method. (That's probably better, because then you won't forget to die if somebody passes a parameter to your reader method, trying to set the attribute.)
You also might want to have a trigger on some other attribute that clears this one.
I keep guessing at what the actual question is, but I have a feeling the following corresponds to it:
package My::M;
use Moose;
use namespace::autoclean;
has 'compiled_regex' => (
isa => 'RegexpRef',
is => 'ro',
writer => '_set_compiled_regex',
);
sub compile {
my $self = shift;
my ($pat) = #_;
$self->_set_compiled_regex(qr/$pat/);
return;
}
__PACKAGE__->meta->make_immutable;
package main;
use strict; use warnings;
my $m = My::M->new;
$m->compile( '^\W+\z' );
if ( '##$%%$' =~ $m->compiled_regex ) {
print "Hmph!\n";
}
Er? If your reader is called get_compiled, and your writer is called _compile, then you don't have a method named compiled_regex, and it should be obvious why a call to that nonexistent method would fail. You need to take several steps back and explain what you're trying to do, instead of what's going wrong with the way you've tried to do it.

How can I extend Moose's automatic pragma exports?

You know how Moose automatically turns on strict and warnings during import? I want to extend that behavior by turning on autodie and use feature ':5.10' in my Moose classes.
I've tracked down where Moose does this, in Moose::Exporter, which assembles a custom import sub for Moose that calls strict->import and warnings->import for the calling class.
However, I can't figure out a way to extend this import method in a Moose-ish way.
How should I handle this?
http://www.friedo.com/bullwinkle.gif
My approach solves the problem backwards.
Why not use ToolSet to create a group of use statements that includes Moose, along with your additional pragmas?
The code should look something like:
# MagicMoose.pm
package MagicMoose;
use base 'ToolSet';
ToolSet->use_pragma( qw/feature :5.10/ ); # perl 5.10
ToolSet->use_pragma( qw/autodie/ );
# define exports from other modules
ToolSet->export(
'Moose' => undef, # get the defaults
);
1; # modules must return true
I haven't tested this. Frankly, I just found ToolSet a few days ago, and haven't had a chance to try it out yet. FWIW, the reviews are positive.
Since there are many ways a module might export its functions into the use-ing namespace, you may need to do some code digging in order to implement each desired library. What you're asking for isn't anything specific to Moose, so you can write your or your company's own best practices module which will set up a group of standards for you to work with, e.g.
use OurCompany::BestPractices::V1;
with
package OurCompany::BestPractices::V1;
use strict;
use warnings;
use feature (':5.10');
require Fatal;
require Moose;
# Required for straight implementation of autodie code
our #ISA;
push #ISA, qw(
Fatal
);
sub import {
my $caller = caller;
strict->import;
warnings->import;
feature->import( ':5.10' );
Moose->import ({into => $caller});
#autodie implementation copied from autodie source
splice(#_,1,0,Fatal::LEXICAL_TAG);
goto &Fatal::import;
}
1;
Autodie makes things a little more complicated since it relies on finding the use-er's package from caller() and uses the goto, but you may be able to find a better way with more testing. The more you implement, the more complicated this library might be, but it might be of high enough value for you to have the one-off solution that you can use within all you or your company's code.
Moose::Exporter will allow you to define a custom import method for a sugar class you're using. MooseX::POE used a version of this for years, but does so in what I consider a "hackish" fashion. Looking at the documentation for Moose::Exporter the following should be roughly what you're asking for
package Modern::Moose;
use Moose ();
use Moose::Exporter;
my ($import) = Moose::Exporter->build_import_methods(
also => 'Moose',
install => [qw(unimport init_meta)],
);
sub import { # borrowing from mortiz's answer for feature/mro
feature->import( ':5.10' );
mro::set_mro( scalar caller(), 'c3' );
goto &$import;
}
This can then be used like so
package MyApp;
use Modern::Moose;
has greeting => (is => 'ro', default => 'Hello');
sub run { say $_[0]->greeting } # 5.10 is enabled
You have to define a sub called import in your package, and import all the other stuff there.
An example from Modern::Perl (another policy module you might look at):
use 5.010_000;
use strict;
use warnings;
use mro ();
use feature ();
sub import {
warnings->import();
strict->import();
feature->import( ':5.10' );
mro::set_mro( scalar caller(), 'c3' );
}
Update: Sorry, didn't read the question carefully enough.
A good way to extend an existing import method is to write your own in a new package, and call Moose's import method from there. You can do that by subclassing, maybe you can even use Moose yourself for that ;-)