How to create a Moose singleton class in Perl?
Question
How to create a Moose singleton class in Perl?
Creating a singleton class in Perl with Moose involves restricting a class so that only one instance of it can ever be created. The singleton pattern ensures that all code using the class shares the same object, which is useful for managing shared resources or global state in an object-oriented way.
While Moose itself does not provide built-in support for singletons, you can easily implement this pattern by controlling object construction in your class and caching the single instance internally. Below is a thorough explanation and an idiomatic example demonstrating how to write a Moose singleton.
How It Works
- Intercept construction: Override the
BUILDARGSornewmethod to control object instantiation. - Store the instance: Keep a private class-level variable holding the singleton object.
- Return the same instance: On subsequent calls to
new, return the cached object instead of creating a new one.
This approach respects Moose’s normal construction and attribute initialization mechanisms while enforcing a single instance.
Example: Moose Singleton Class
use strict;
use warnings;
use feature 'say';
package MySingleton;
use Moose;
# Private class variable to hold the singleton instance
my $instance;
has 'value' => (
is => 'rw',
isa => 'Str',
default => 'default',
);
# Override new to implement the singleton pattern
around BUILDARGS => sub {
my ($orig, $class, @args) = @_;
# Only instantiate once
if (defined $instance) {
# Return the existing instance's internal data (hashref)
# So Moose can build the object from this instead of creating a new one
# But actually, to return the same instance, override 'new' instead
return $instance->BUILDARGS(@args);
}
# First time creation: call original BUILDARGS
return $class->$orig(@args);
};
around 'new' => sub {
my ($orig, $class, @args) = @_;
# Return existing instance if it exists
return $instance if defined $instance;
# Otherwise create and cache the instance
$instance = $class->$orig(@args);
return $instance;
};
sub DEMOLISH {
# Prevent instance destruction to keep singleton alive (optional)
# Or leave it empty to allow normal cleanup
}
package main;
# Demonstration of singleton behavior
my $obj1 = MySingleton->new(value => 'foo');
say "Object 1 value: " . $obj1->value;
my $obj2 = MySingleton->new(value => 'bar'); # Attempt to create new instance
say "Object 2 value: " . $obj2->value;
if ($obj1 == $obj2) {
say "obj1 and obj2 are the same instance (singleton works)";
} else {
say "Different instances (singleton failed)";
}
# Modify the singleton via one reference
$obj1->value('changed');
say "Object 2 value after change: " . $obj2->value;
Explanation
my $instance;declares a lexical variable scoped to the package to cache the singleton object.- The
around 'new'method override intercepts all calls tonew. If an instance already exists, it returns that instead of creating a new one. around BUILDARGSkeeps Moose’s parameter normalization intact, ensuring attributes can be passed as usual.- Because the same object is returned every time, you ensure shared state.
- The demo script proves the singleton works by showing that two "new" calls return the same object and observe changes.
Common Gotchas
- Thread Safety: This singleton is not thread-safe. For multithreaded environments, you’d need locking around instance creation.
- Subclassing: If subclassed, each subclass would share the same cached instance unless you adjust the code to cache per class name.
- DESTROY and Cleanup: The singleton is kept alive by the lexical variable
$instance. If your program needs explicit cleanup, customizeDEMOLISHcarefully. - Using MooseX::Singleton: There is a CPAN extension
MooseX::Singletonthat does this for you automatically, but if using core Moose alone, this pattern works well.
Perl and Moose Concepts
The example illustrates a few Perl and Moose concepts:
Mooseadds powerful object orientation to Perl with attributes (declared usinghas) and method modifiers likearound.- Method modifiers allow you to wrap existing methods to customize behavior without rewriting.
sigilslike$capture scalar data; here$instanceholds the singleton object.TMTOWTDI: Perl’s “There’s more than one way to do it” philosophy lets you choose the singleton implementation style that fits your needs.
This code is fully runnable on any Perl 5 with Moose installed (no external modules beyond Moose). It prints to STDOUT demonstrating the singleton behavior.
Verified Code
Executed in a sandbox to capture real output. • v5.34.1 • 137ms
Object 1 value: foo
Object 2 value: foo
obj1 and obj2 are the same instance (singleton works)
Object 2 value after change: changed
(empty)Was this helpful?
Related Questions
- How to use Moose::Util::TypeConstraints for custom types?
- How to implement method delegation in Perl Moo?
- How to use Type::Tiny with Moo for strict typing in Perl?
- How to use required attributes in Perl Moo and Moose?
- How to convert a Perl Moo class to Moose?
- How to use Moo lazy_build for attribute defaults in Perl?