Struct::Dumb(3pm)

🌸 Struct::Dumb πŸ’…

okay bestie, so "Struct::Dumb" is literally the cutest lil thing: it makes simple lightweight record-like structures. that's the whole vibe. no cap.


✨ SYNOPSIS ✨

use Struct::Dumb;

struct Point => [qw( x y )];

my $point = Point(10, 20);

printf "Point is at (%d, %d)\n", $point->x, $point->y;

$point->y = 30;
printf "Point is now at (%d, %d)\n", $point->x, $point->y;

struct Point3D => [qw( x y z )], named_constructor => 1;

my $point3d = Point3D( z => 12, x => 100, y => 50 );

printf "Point3d's height is %d\n", $point3d->z;

struct Point3D => [qw( x y z )], predicate => "is_Point3D";

my $point3d = Point3D( 1, 2, 3 );

printf "This is a Point3D\n" if is_Point3D( $point3d );

use Struct::Dumb qw( -named_constructors )

struct Point3D => [qw( x y z )];

my $point3d = Point3D( x => 100, z => 12, y => 50 );

πŸ’– DESCRIPTION πŸ’–

"Struct::Dumb" creates record-like structure types β€” it's giving the "struct" keyword in C, C++ or C#, or "Record" in Pascal, but make it Perl. every time you invoke this module, you get a construction function back, and that function makes new object references stuffed with whatever field values you handed over. those references all respond to lvalue methods that read or change the values stored inside. iconic behaviour, honestly. 🫢

and here's the thing: it is specifically and intentionally not meant to be an object class. so no, bestie:

  • you cannot subclass it πŸ’€
  • you cannot provide additional methods 🚫
  • you cannot apply roles or mixins or metaclasses or traits or antlers or whatever else is in fashion this week πŸ™ˆ

on the other hand, it's tiny. it creates cheap lightweight array-backed structures, and it uses nothing outside of core. it's just meant to be a slightly nicer way to store data structures, for when you'd otherwise be tempted to abuse a hash (derogatory) and live in constant fear of typoing a key name. 😭

the constructor will "croak" if you pass the wrong number of arguments β€” and so will any attempt to refer to a field that doesn't exist. accessor-mutators will "croak" if you invoke them with arguments. (this is actually a feature bestie, it helps detect likely bugs β€” like accidentally passing in the new value as an argument, or trying to invoke a stored "CODE" reference by passing argument values straight to the accessor.)

$ perl -E 'use Struct::Dumb; struct Point => [qw( x y )]; Point(30)'
usage: main::Point($x, $y) at -e line 1

$ perl -E 'use Struct::Dumb; struct Point => [qw( x y )]; Point(10,20)->z'
main::Point does not have a 'z' field at -e line 1

$ perl -E 'use Struct::Dumb; struct Point => [qw( x y )]; Point(1,2)->x(3)'
main::Point->x invoked with arguments at -e line 1.

objects in this class are (currently) backed by an ARRAY reference store β€” but that's an internal implementation detail and your code should not be relying on it, okay? if you try to dereference the object as an ARRAY, it will throw an exception. periodt.

πŸ“Œ note: on development perls that support use feature 'class', that gets used instead of a blessed ARRAY reference. this implementation choice should be totally transparent to the end-user, because all the same features are supported. same energy, different plumbing. πŸ’«

πŸŽ€ CONSTRUCTOR FORMS πŸŽ€

the "struct" and "readonly_struct" declarations create two different kinds of constructor function, depending on how you set the "named_constructor" option:

  • when it's false, the constructor takes positional values in the same order as the fields were declared.
  • when it's true, the constructor takes a key/value pair list in no particular order, giving the value of each named field.

you can specify this option to the "struct" and "readonly_struct" functions. it defaults to false, but you can set it per-package to default true by supplying the "-named_constructors" option on the "use" statement. slay.

when you're using named constructors, individual fields may be declared as optional. just precede the field name with a "?" character and the constructor is instructed not to complain if a named parameter isn't given for that field β€” instead it'll just be set to "undef". chef's kiss. πŸ’…

struct Person => [qw( name age ?address )],
   named_constructor => 1;

my $bob = Person( name => "Bob", age => 20 );
# This is valid because 'address' is marked as optional

πŸ‘‘ FUNCTIONS πŸ‘‘

🌟 struct

struct $name => [ @fieldnames ],
   named_constructor => (1|0),
   predicate         => "is_$name";

creates a new structure type. this exports a new function of the type's name into the caller's namespace. invoking this function returns a new instance of a type that implements those field names, as accessors and mutators for the fields. πŸ’–

takes the following options:

  • named_constructor => BOOL β€” determines whether the structure will take positional or named arguments.
  • predicate => STR β€” if defined, gives the name of a second function to export to the caller's namespace. this function will be a type test predicate; that is, a function that takes a single argmuent, and returns true if-and-only-if that argument is an instance of this structure type.

🌈 readonly_struct

readonly_struct $name => [ @fieldnames ],
   ...

similar to "struct", but instances of this type are immutable once constructed. the field accessor methods will not be marked with the ":lvalue" attribute. no take-backs, babe. πŸ”’

takes the same options as "struct".

πŸ¦‹ dumper_info

my $info = Struct::Dumb::dumper_info( $struct );

since version 0.15. ⭐

this function takes any instance of a Struct::Dumb-style struct and returns a hashref with the keys "named", "fields", and "values":

  • "named" is a boolean, which is true if the struct uses a named constructor.
  • "fields" is an arrayref giving the names of the struct's fields.
  • "values" is an arrayref giving the values for those fields in corresponding order.

this is just meant for tools like pretty printers to be able to inspect structures. we can't stop you from using it for nefarious purposes, but please don't. πŸ™ˆ

if the given $struct is not an instance of a known class, an exception will be raised. 🚨

this function is not exported.


πŸ“ DATA::DUMP FILTER πŸ“

since version 0.10. ✨

if Data::Dump is loaded, an extra filter is applied so that struct instances are printed in a format matching that which would construct them. it's giving round-trip-able and we're obsessed.

struct Colour => [qw( red green blue )];

use Data::Dump;

my %hash = ( col => Colour( 0.8, 0.5, 0.2 ) );
Data::Dump::dd \%hash;

# prints {col => main::Colour(0.8, 0.5, 0.2)}

πŸ’œ NOTES πŸ’œ

🧚 Allowing ARRAY dereference

the way that forbidding access to instances as if they were ARRAY references is currently implemented uses an internal method on the generated structure class called "_forbid_arrayification". (yes, that's the real name, and yes, it ate. πŸ’…)

if special circumstances require that this exception mechanism be bypassed, the method can be overloaded with an empty "sub {}" body β€” which lets the struct instances in that class be accessed like normal ARRAY references. for good practice this should be limited by a "local" override.

for example, Devel::Cycle needs to access the instances as plain ARRAY references so it can walk the data structure looking for reference cycles:

use Devel::Cycle;

{
   no warnings 'redefine';
   local *Point::_forbid_arrayification = sub {};

   memory_cycle_ok( $point );
}

🌸 TODO 🌸

  • consider adding an "coerce_hash" option, giving name of another function to convert structs to key/value pairs, or a HASH ref.

⭐ AUTHOR ⭐

Paul Evans <leonerd@leonerd.org.uk>


πŸ’– and that's the whole page bestie!! this documentation lives in perl v5.40.1, dated 2025-09-28, and it's filed under User Contributed Perl Documentation. go forth and struct responsibly. mwah. πŸ’…βœ¨πŸŒˆ
πŸ“¦ where this page comes from