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:

  • Any

  • Defined

  • Str

  • Int

  • Num

  • Bool

  • ArrayRef

  • HashRef

  • CodeRef

  • Object

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:

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