NAME
Object::Proto::Sugar - Moo-se-like syntax for Object::Proto
VERSION
Version 0.01
SYNOPSIS
package Animal;
use Object::Proto::Sugar;
has name => (
is => 'rw',
isa => Str,
required => 1
);
has sound => (
is => 'rw',
isa => Str,
default => 'silence'
);
sub speak {
$_[0]->sound
}
package Dog;
use Object::Proto::Sugar;
extends 'Animal';
has breed => (
is => 'rw',
isa => Str
);
package main;
my $dog = new Dog name => 'Rex', sound => 'woof', breed => 'Lab';
print $dog->speak; # woof
print $dog->isa('Animal'); # 1
DESCRIPTION
Object::Proto::Sugar provides Moo-se-like declarative syntax over Object::Proto, giving you has, extends, with, requires, method modifiers, and type constants — all compiled down to the zero-overhead XS layer underneath.
KEYWORDS
has $name => (%options)
Declares an attribute. All options are optional unless noted.
has age => (
is => 'rw', # 'rw' (read-write) or 'ro' (read-only)
isa => Int, # type constraint (string or constant)
required => 1, # must be supplied to constructor
default => 0, # default value when parsed a codeblock it's actually installed as a builder
lazy => 1, # compute default on first access
builder => '_build_age',# method name (or 1 for _build_$name)
coerce => sub { ... }, # coerce incoming value
trigger => sub { ... }, # called after value is set
predicate => 1, # install has_$name (or custom name)
clearer => 1, # install clear_$name (or custom name)
reader => 1, # install get_$name (or custom name)
writer => 1, # install set_$name (or custom name)
init_arg => '_age', # constructor key (alias: arg)
weak_ref => 1, # store a weak reference (alias: weak)
);
is
is => 'rw' # read-write accessor
is => 'ro' # read-only (setter dies)
isa
Accepts a built-in type constant, a type name string, or a custom coderef:
isa => Str # built-in type constant
isa => 'Str' # same, as above
isa => sub { $_[0] > 0 } # custom check — dies on failure
default
default => 42 # scalar
default => 'text' # string
default => [] # fresh arrayref per object
default => {} # fresh hashref per object
default => sub { ... } # coderef — called as builder
builder
builder => 1 # calls _build_$name on the object
builder => '_my_builder' # calls named method on the object
builder => sub { ... } # anonymous sub installed as builder
predicate and clearer
predicate => 1 # installs has_$name
predicate => 'is_set' # installs is_set
clearer => 1 # installs clear_$name
clearer => 'reset_age' # installs reset_age
reader and writer
reader => 1 # installs get_$name
reader => 'fetch_age' # installs fetch_age
writer => 1 # installs set_$name
writer => 'store_age' # installs store_age
accessor
Install a function-style accessor for maximum performance. The function can be called as fname($obj) (get) or fname($obj, $value) (set), avoiding method dispatch overhead entirely.
accessor => 1 # installs function named after the attribute
accessor => 'fname' # installs function with custom name
Unlike reader/writer, accessor installs a single combined get/set function. reader and writer also install function-style versions alongside their method-style ones when specified.
has age => ( is => 'rw', accessor => 1 );
# method style: $obj->age
# function style: age($obj) or age($obj, 42)
has age => ( is => 'rw', reader => 1, writer => 1 );
# method style: $obj->get_age, $obj->set_age
# function style: get_age($obj), set_age($obj, 42)
init_arg / arg
Override the constructor key used to populate this attribute:
has name => ( is => 'rw', init_arg => '_name' );
# new MyClass _name => 'Alice'
arg is an alias for init_arg.
weak_ref / weak
Store a weak reference. The attribute becomes undef when the referent is garbage-collected:
has parent => ( is => 'rw', weak_ref => 1 );
weak is an alias for weak_ref.
extends @parents
Inherit from one or more Object::Proto classes. Parent slots are copied into the child at define time; @ISA is set up for method dispatch.
extends 'Animal';
extends 'Animal', 'Flyable'; # multiple inheritance
The parent class must have been defined with Object::Proto::Sugar (or Object::Proto::define) before the child's package is compiled.
with @roles
Compose one or more roles into the current class (or role):
with 'Printable';
with 'Printable', 'Serializable';
The role must have been defined before the consuming class.
requires @methods
Declare methods that a consuming class must implement. Only meaningful inside a role (use Object::Proto::Sugar -role):
requires 'name';
requires 'to_string', 'to_hash';
before $method => sub { ... }
Run code before the named method. Receives the same arguments as the method.
before 'save' => sub {
my ($self) = @_;
$self->updated_at(time);
};
after $method => sub { ... }
Run code after the named method. Receives the same arguments as the method.
after 'save' => sub {
my ($self) = @_;
log_action('saved ' . $self->name);
};
around $method => sub { ... }
Wrap a method. The wrapper receives $orig as its first argument:
around 'greet' => sub {
my ($orig, $self, @args) = @_;
return uc $self->$orig(@args);
};
Multiple modifiers can be stacked. before modifiers run in reverse declaration order; after modifiers run in declaration order.
The $method name may be unqualified (resolved to the current package) or fully qualified ('Other::Package::method').
ROLES
Define a role by passing -role to the import:
package Printable;
use Object::Proto::Sugar -role;
requires 'name';
has format => ( is => 'rw', default => 'text' );
sub print_self { $_[0]->name . ' (' . $_[0]->format . ')' }
Consume it with with:
package Document;
use Object::Proto::Sugar;
with 'Printable';
has name => ( is => 'rw', isa => Str );
Check consumption at runtime:
Object::Proto::does($doc, 'Printable'); # true
TYPE CONSTANTS
use Object::Proto::Sugar exports a constant for every registered type into the calling package, so you can write:
isa => Str
isa => ArrayRef
instead of:
isa => 'Str'
isa => 'ArrayRef'
The built-in constants are:
AnyDefinedStrIntNumBoolArrayRefHashRefCodeRefObject
Custom types registered with Object::Proto::register_type before use Object::Proto::Sugar is called will also get a constant exported.
INHERITANCE
Single parent
package Dog;
use Object::Proto::Sugar;
extends 'Animal';
has breed => ( is => 'rw', isa => Str );
Dog inherits all of Animal's slots and methods. Inherited slots occupy the same positions as in the parent so there is no runtime overhead for access.
Multiple parents
extends 'Animal', 'Flyable';
Parent slots are merged left-to-right. A child slot with the same name as a parent slot overrides it.
BENCHMARK
Test: new + set + get
------------------------------------------------------------
Benchmark: running Moo, Mouse, Sugar, Sugar (fn) for at least 3 CPU seconds...
Moo: 3 wallclock secs ( 3.09 usr + 0.00 sys = 3.09 CPU) @ 1264320.39/s (n=3906750)
Mouse: 4 wallclock secs ( 3.15 usr + 0.00 sys = 3.15 CPU) @ 1290237.46/s (n=4064248)
Sugar: 4 wallclock secs ( 3.01 usr + 0.00 sys = 3.01 CPU) @ 2784378.41/s (n=8380979)
Sugar (fn): 4 wallclock secs ( 3.11 usr + 0.00 sys = 3.11 CPU) @ 3174092.93/s (n=9871429)
Rate Moo Mouse Sugar Sugar (fn)
Moo 1264320/s -- -2% -55% -60%
Mouse 1290237/s 2% -- -54% -59%
Sugar 2784378/s 120% 116% -- -12%
Sugar (fn) 3174093/s 151% 146% 14% --
AUTHOR
LNATION <email@lnation.org>
BUGS
Please report any bugs or feature requests to bug-object-proto-sugar at rt.cpan.org, or through the web interface at https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Object-Proto-Sugar. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
SUPPORT
You can find documentation for this module with the perldoc command.
perldoc Object::Proto::Sugar
You can also look for information at:
RT: CPAN's request tracker (report bugs here)
https://rt.cpan.org/NoAuth/Bugs.html?Dist=Object-Proto-Sugar
Search CPAN
LICENSE AND COPYRIGHT
This software is Copyright (c) 2026 by LNATION <email@lnation.org>.
This is free software, licensed under:
The Artistic License 2.0 (GPL Compatible)
1 POD Error
The following errors were encountered while parsing the POD:
- Around line 400:
Non-ASCII character seen before =encoding in '—'. Assuming UTF-8