MooseX:...ruction(3)

πŸ“¦
version 0.35 Β· 2 versions
, in fedora 43

✨ MooseX::Extended::Manual::Construction ✨

okay bestie, gather round, because today we're talking about object construction in MooseX::Extended and honestly? it's giving glow up. πŸ’…


🌸 VERSION 🌸

version 0.35 β€” yes she's got a number, respect her πŸ’–


πŸŽ€ OBJECT CONSTRUCTION πŸŽ€

so the classics β€” new, BUILD, and BUILDARGS β€” all do their normal thing, no drama, no notes. 🫢

BUT. (there's always a but, bestie 😭) we slap MooseX::StrictConstructor on top to dodge this exact tragedy:

my $soldier = Soldier->new(
    name   => $name,
    rank   => $rank,
    seriel => $serial, # should be serial
);

like… seriel?? ma'am?? 🫠 by default, if you misspell an argument to the Moose constructor, it just gets silently discarded β€” and then you're three hours deep debugging a bug that was literally a typo the whole time. lowkey devastating. but with MooseX::Extended? that misspelled arg is a fatal error, periodt. no silent ghosts, no mystery bugs. πŸ”₯

now, if you actually need to pass arbitrary "sideband" data, just declare it out loud like the main character you are:

param sideband => ( isa => HashRef, default => sub { {} } );

and naturally β€” because we bundle MooseX::Extended::Types β€” you can go way more granular on validating that data if you want. slay. ✨


πŸ’– FUNCTIONS πŸ’–

these two cuties get exported straight into your namespace. you're welcome. πŸŽ€

🌈 param

param name => ( isa => NonEmptyStr );

it's basically Moose's has but with ✨attitude✨. a param is required. you can pass it to the constructor, or hand it a default or a builder to supply the value.

that lil definition up there? it's equivalent to:

has name => (
    is       => 'ro',
    isa      => NonEmptyStr,
    required => 1,
);

want a param with no default and no builder, that can optionally be passed to the constructor? just say required => 0, easy:

param title => ( isa => Str, required => 0 );

okay important: param, just like field, defaults to read-only β€” is => 'ro'. you can override it:

param name => ( is => 'rw', isa => NonEmptyStr );

but otherwise it behaves exactly like has, so you can pass in literally any arguments has accepts. go off. πŸ’…

# we'll make it private, but allow it to be passed to the constructor
# as `name`
param _name   => ( isa => NonEmptyStr, init_arg => 'name' );

πŸ¦‹ field

field created => ( isa => PositiveInt, default => sub { time } );

also similar to Moose's has, but a field is almost never allowed to be passed to the constructor. default and builder still work exactly as normal though. πŸ’œ

that field definition is equivalent to:

has created => (
    is       => 'ro',
    isa      => PositiveInt,
    init_arg => undef,        # not allowed in the constructor
    default  => sub { time },
    lazy     => 1,
);

and yes, field β€” same as param β€” defaults to read-only, is => 'ro'. override whenever:

field some_data => ( is => 'rw', isa => NonEmptyStr );

otherwise it's just has energy, any arguments has accepts are fair game.

WARNING 🚨 bestie listen: if you pass field an init_arg with a defined value, the code will croak β€” unless that value begins with an underscore. no cap.
field created => (
    isa      => PositiveInt,
    default  => sub {time},
    lazy     => 0,             # because it must fire at object creation
    init_arg => '_created',    # but let them override this in tests
);

that one lets you pass _created => 42 in the constructor β€” which is so handy when you wanna control that value for tests. 🧚

other than that? a field is just internal instance data for the class. it's not meant to be passed to the constructor. if that's what you want, use param, bestie, that's literally what she's for. 🌸

⭐ Lazy Fields

a field is automatically lazy if it has a builder or a default β€” because like, there's no guarantee the code will ever call them? but that's also what makes it so easy for a field to rely on a param value being present. iconic, honestly. πŸ‘‘

but heads up: this does mean that if you need a field to be initialized at construction time, you have to take care yourself:

has created => ( isa => PositiveInt, lazy => 0, default => sub {time} );

no param is lazy by default, but you can add lazy => 1 if you need to. simple as. ✨


πŸ’€ AUTHOR πŸ’€

Curtis "Ovid" Poe <curtis.poe@gmail.com>


This software is Copyright (c) 2022 by Curtis "Ovid" Poe.

This is free software, licensed under:

The Artistic License 2.0 (GPL Compatible)

and that's the whole page, babe πŸŽ€ this was written for perl v5.42.0 and dated 2025-07-25, so like, go forth and construct your objects with ✨zero typos✨ and maximum main character energy. mwah. πŸ’–πŸ¦‹πŸ’…

πŸ“¦ where this page comes from