What's the best practice for implementing Singletons in Perl?
You can use the Class::Singleton module.
A "Singleton" class can also be easily implemented using either my or state variable (the latter is available since Perl 5.10). But see the #Michael's comment below.
package MySingletonClass;
use strict;
use warnings;
use feature 'state';
sub new {
my ($class) = #_;
state $instance;
if (! defined $instance) {
$instance = bless {}, $class;
}
return $instance;
}
If you're using Moose, then MooseX::Singleton. Its interface is compatible with Class::Singleton.
Singleton Summary:
Most of the time a normal object will work.
Be careful with singletons.
Localize interaction as much as possible
While singletons are a nice idea, I tend to just implement a normal object and use it. If it is critical that I only have one such object, I'll modify the constructor to throw a fatal exception when the second object is created. The various singleton modules don't seem to do much besides add a dependency.
I do this because it is easy, it works, and when in some weird future I need to work with a second object in my app, the changes are minimized.
I also like to localize interaction with my 'singleton' objects--keep interaction in as few places as possible. So instead of every object having direct access to the singleton, I mediate all interaction through my "Application" object. Whenever possible, the application object gets data from the 'singleton', and passes it as a parameter to the method in the other objects. Responses from other objects may also be munged and passed to the 'singleton'. All this effort helps when I need to make changes in the 'singleton' object, and when I want to reuse other objects in another app that may not need or be able to use the original 'singleton' object.
Related
I am writing a file manager for my Perl application. Information about each file is kept as an object. When I remove a file, I'd like to change the corresponding object's class to RemovedFile. For this class, call to any valid method of "File" would return a fatal error and a stack trace. This would be to catch cases where some stale reference to this object is kept (while it shouldn't).
I thought about two ways I could implement this:
"RemovedFile" inherits from "File" and redefines all its methods with a call to fatal error. Downside to this is that if I add a new method to "File" I need to add it to "RemovedFile" as well.
Adding a call to some empty method to every method of "File". "RemovedFile" would redefine this one method to report fatal error. (See code below for an example of what I mean). Downside to this is that every method of "File" would have to be bothered with calling the "remove_guard" in the beginning which IMO is not very clean.
# Inside File class:
sub any_method_of_file_class {
$self->_removed_guard();
#rest of code
}
sub _removed_guard {
#do nothing
}
# Inside RemovedFile class redefine only _removed_guard:
sub _removed_guard {
$self->{logger}->fatal_with_stack_trace();
}
I wanted to ask if there is any better way to implement this kind of behaviour in Perl?
For example, could I use some tricks to first list and then dynamically redefine all methods of a parent class without specifying their exact names?
You can define the RemovedFile class without any relation to the original File class. In RemovedFile, use AUTOLOAD to handle any method.
If you want to redefine (override) all the methods of the parent class, don't inherit from the parent class. You can use the same interface, but you don't need the connection to some module you are going to completely ignore.
I think I'd probably have a factory method in File that returns a new object for RemovedFile:
my $removed_file_obj = $file->remove;
That new class only knows what it needs to know about removed files. The remove can do whatever cleanup you require.
Then, when you are dealing with lists of objects, some of which may be File and some of which may be RemovedFile, filter the ones you want. This is outside of the class definitions because the class only defines the behavior of the objects and not how we employ the objects.
Here's one way to check by the object type, maybe even with the new isa feature:
use v5.32;
use experimental qw(isa);
foreach my $file ( #files ) {
# next if $file->isa( 'RemovedFile' );
next if $file isa 'RemovedFile';
...
}
But, you probably shouldn't check what something is. Check what it can do. Since you haven't inherited a bunch of methods that don't do anything, can should return false for that:
foreach my $file ( #files ) {
next if $file->can( 'some_method_not_in_RemovedFile' );
...
}
I wish I knew the reference or document that told me that this is the best way to create a new object in Perl:
sub new {
my $package = shift;
my $class = ref($package) || $package
This is how I've been creating objects for years but now I'm wondering why go to the trouble? With the exception of some edge cases why not simply do the following:
sub new {
shift; # get rid of the object or package name
my $class = __PACKAGE__;
Are there any issues with simply doing using __PACKAGE__ when there's no special reason to try to detect what namespace the 'new' method is being called in?
Inheritance
# classA.pm
package ClassA;
sub new { $pkg = ref($_[0]) || $_[0] ; bless { foo => 42 }, $pkg }
# classB.pm
package ClassB;
use parent 'ClassA';
sub foo { ... }
# main.pl
use ClassA;
use ClassB;
$B = ClassB->new();
print $B->foo();
In this example, ClassB inherits methods from ClassA, including its constructor. But we still want to identify the object as belonging to ClassB, so the constructor in ClassA must respect the name of the reference passed to its constructor.
Easier and safer than
$B = bless { ClassA->new(), "ClassB" }; # or
$B = bless { ClassB->new(), "ClassA" };
or adding a pass-though constructor in ClassB.
package ClassB;
use parent 'ClassA';
sub new { bless { ClassA::new(#_), __PACAKGE__ } }
The class name is already the first argument to the constructor, so why not use that? You don't need to reach for anything and if you decide that the situation is more complex than you originally envisioned, you haven't artificially caused a speed bump. This code works with or without inheritance:
sub new {
my( $class, #args ) = #_;
...
bless {...}, $class;
}
Consider with anything that you program how much you'd have to change if the code situation changed. Maybe you add a couple of extra steps that you don't immediately need, but that keeps the code flexible for those times when you realize you actually needed those cases. In your case, you actually have to do extra work to ignore the invocant argument that Perl specifically provides to tell you which class is trying to mak a new object.
For example, you create your class, it works for you and does its job well. It works so well that you share it and someone else uses it and they are mostly happy with it for awhile until they need this one little modification. They should be able to subclass your module (so, no changes to it or for you) to extend or override a method. But, your code doesn't allow that because you blessed the object in a more restrictive way that didn't add any benefit.
That first bit of code in your question is using the first argument too, but it's not really a prescription for constructors. It's doing an extra thing by allowing an already existing object create a new one. The ref extracts the blessed package name from the object and uses that for the new object.
I don't particularly like that way of creating new objects and I think the interface will likely confuse people. What should happen when you call new on an existing object? Do you clone the existing one? If so, there are better names, such as clone (Ruby uses dup). Do you get a completely fresh object? If so, why do you go through an existing object to get one completely unrelated to it?
There was a time that many examples of OO Perl showed that same sort of constructor, and it was copy and pasted into many places. But we've learned a lot since then. Maybe you have a good answer why you'd allow that, but so far I haven't heard a compelling one.
I would like you to share your experience on the matter of using some common object by different components of a library (or an application). I'd like to understand, which practice is better, which way is more "ecological".
Let's imagine that we have some complex library that consists of a bunch of classes: Library, Library::Foo, Library::Foo::Bar and many other ones. An application that uses the library initializes a Library-classed object, at some stage this object initializes some quantity of Library::Foo-classed objects, they initialize Library::Foo::Bar-classed objects and so on.
And now let's imagine that there is the Library::Logger class that is being used by all components. It's being initialized only once by the constructor of the Library class and all other sub-classes need it for their logging purposed.
The question is: how to let them all have the reference to this object?
I see the following ways to acheive it:
Passing it to the constructor
When a Library-based object initializes a Library::Foo-classed object, it passes the reference to the logger to the newly-created object as a parameter:
$self->_set_logger(Library::Logger->new());
my $logger = $self->_get_logger;
my $foo = Library::Foo->new(logger => $logger);
So the Library::Foo-classed object could get the logger and even pass it to a Library::Foo::Bar-classed object when it's needed:
my $logger = $self->_get_logger;
my $bar = Library::Foo::Bar(logger => $logger);
Accessing it as a method
When a Library-based object initializes the Library::Foo-based object, it passes the reference to itself to the newly-created object:
$self->_set_logger(Library::Logger->new());
my $foo = Library::Foo->new(papa => $self);
So the Library::Foo-based object could access the logger this way:
$my logger = $self->_get_papa->_get_logger;
my $bar = Library::Foo::Bar(papa => $self);
It breaks encapsulation, but it also lets the Library::Foo-based object to get other data from its "papa".
Using a global variable
Also we can store the reference to the logger in some global variable, so any other object could access it this way:
$logger = $Library::_LOGGER;
Well, it really sucks, I know... :)
...
So, what do you think, which way seems to be better? What alternative way would you propose? How do you solve this problem for yourself? Would you pass the data to the "child" manually or would you let it to get the data from the "parent"?
Many thanks in advance!
There is no answer to your problem. It realy depends on your exact use-case. If (just guessing) you only want to have exactly one Logger in your Library, I think using the software pattern of a "singleton" might exactly fit. E.g.
package Library::Logger;
use strict;
my $logger;
sub new {
unless ($logger) {
.... initializing $logger ...
}
return $logger;
}
and in each of your sublclasses you can access it by
Library::Logger->new()->...
HTH
Georg
We have following code structure in our code
namedParamJdbcTemplate.query(buildMyQuery(request),new MapSqlParameterSource(),myresultSetExtractor);
and
namedParamJdbcTemplate.query(buildMyQuery(request),new BeanPropertySqlParameterSource(mybean),myresultSetExtractor);
How can I expect these method calls without using isA matcher?
Assume that I am passing mybean and myresultSetExtractor in request for the methods in which above code lies.
you can do it this way
Easymock.expect(namedParamJdbcTemplateMock.query(EasyMock.anyObject(String.class),EasyMock.anyObject(Map.class),EasyMock.anyObject(ResultSetExtractor.class))).andReturn(...);
likewise you can do mocking for other Methods as well.
hope this helps!
good luck!
If you can't use PowerMock to tell the constructors to return mock instances, then you'll have to use some form of Matcher.
isA is a good one.
As is anyObject which is suggested in another answer.
If I were you though, I'd be using Captures. A capture is an object that holds the value you provided to a method so that you can later perform assertions on the captured values and check they have the state you wanted. So you could write something like this:
Capture<MapSqlParameterSource> captureMyInput = new Capture<MapSqlParameterSource>();
//I'm not entirely sure of the types you're using, but the important one is the capture method
Easymock.expect(namedParamJdbcTemplateMock.query(
EasyMock.anyObject(Query.class), EasyMock.capture(captureMyInput), EasyMock.eq(myresultSetExtractor.class))).andReturn(...);
MapSqlParameterSource caughtValue = captureMyInput.getValue();
//Then perform your assertions on the state of your caught value.
There are lots of examples floating around for how captures work, but this blog post is a decent example.
I have a Moose::Role that contains a network client as an attribute:
package Widget;
use Moose::Role;
has 'network_thingy' => (
isa => Maybe[ThingyClient],
);
And of course, I have a couple concrete Moose classes which use this role:
package BlueWidget;
use Moose;
with 'Widget';
Now it comes to functional testing of the Widgets. We have the ability to create ThingyServer objects, and it would be much faster and overall excellent to directly use ThingyServer objects instead of spinning up a daemon and having a ThingyClient connect to it over the network. Since ThingyClient & ThingyServer conveniently have the exact same methods, this should be easily possible. But of course, Moose is demanding that I use a ThingyClient when the test eventually constructs a BlueWidget.
I did some research, and came across the Moose::Meta documentation. Seemed perfect! So here's the test code:
my $metarole = Moose::Meta::Role->initialize('Widget');
// first remove the old attribute
$metarole->remove_attribute('network_thingy');
I was going to add a new attribute, but I thought I'd check on the state of the role & class first. Now if I dump out the $metarole, it looks great. There's no network_thingy attribute anymore. But if I construct a BlueWidget class, or just peak inside the metaclass...
$metaclass = Moose::Meta::Class->initialize('BlueWidget');
diag Dumper ($metaclass);
... sure enough network_thingy is still there. This is not at all what I expected. How can I modify/remove/replace an attribute of the Widget role at runtime?
When a class consumes a role, attributes are copied from the role to the class. If you then change the attribute in the role, the copy in the class is unaffected.
So you would need to loop through the classes that have consumed the role, and change the attribute in each class. There's a consumers method in Moose::Meta::Role that could help you get a list of classes that have consumed the role, however it only covers classes that have directly consumed the role, and not, say, subclasses of those.
If the classes have been made immutable (__PACKAGE__->meta->make_immutable), you'll need to make them mutable again before you make modify the attribute.
Overall, it's probably a better idea to just alter the role module (i.e. edit the file); not attempt to tweak the attribute at run time. Maybe set isa to a duck_type type constraint?