I am new to perl and still learning oop in perl. I usually code in C, C++. It is required to bless an object to notify perl to search for methods in that package first. That's what bless does. And then every function call made with help of -> passes the instance itself as first parameter. Now I have a doubt in writing the constructor for a new object. Normally a constructor would normally look like:
sub new {
my %hash = {};
return bless {%hash}; #will automatically take this package as the class
}
Now I want to have two data members in my class so I can do something like this:
sub new {
my %hash = {};
$hash->{"table_header"} = shift #_; #add element to hash
$hash->{"body_content"} = shift #_;
return bless {%hash}; #will automatically take this package as the class
}
My question is that is this the only possible way. Can't we have multiple data members like in C and C++ and we do have to use strings like "table_header" and "body_content".
EDIT:
In C or C++ we can directly reference the data member(assume its public for now). Here there is one extra reference which has to be made. I wanted to know if there is any way we can have a C like object.
sub new {
my $table_header = shift #_;
my $body_content = shift #_;
#bless somehow
}
Hope this clears some confusion.
There are modules that make OOP in Perl easier. The most important is Moose:
use strict; use warnings;
package SomeObject;
use Moose; # this is now a Moose class
# declare some members. Note that everything is "public"
has table_header => (
is => 'ro', # read-only access
);
has body_content => (
is => 'rw', # read-write access
);
# a "new" method is autogenerated
# some method that uses these fields.
# Note that the members can only be accessed via methods.
# This guards against typos that can't be easily caught with hashes.
sub display {
my ($self) = #_;
my $underline = "=" x (length $self->table_header);
return $self->table_header . "\n" . $underline . "\n\n" . $self->body_content . "\n";
}
package main;
# the "new" takes keyword arguments
my $instance = SomeObject->new(
table_header => "This is a header",
body_content => "Some body content",
);
$instance->body_content("Different content"); # set a member
print $instance->display;
# This is a header
# ================
#
# Different content
If you get to know Moose, you will find an object system that is far more flexible than that in Java or C++, as it takes ideas from Perl6 and the Common Lisp Object System. Of course, this is fairly ugly, but it works well in practice.
Because of the way Perl OOP works, it isn't possible to have the instance members accessible as variables on their own. Well, almost. There is the experimental mop module which does exactly that.
use strict; use warnings;
use mop;
class SomeObject {
# Instance variables start with $!..., and behave like ordinary variables
# If you make them externally accessible with "is ro" or "is rw", then
# appropriate accessor methods are additionally generated.
# a private member with public read-only accessor,
# which has to be initialized in the constructor.
has $!table_header is ro = die 'Please specify a "table_header"!';
# a private member with public read-write accessor,
# which is optional.
has $!body_content is rw = "";
# new is autogenerated, as in Moose
method display() {
# arguments are handled automatically, so we could also do $self->table_header.
my $underline = "=" x (length $!table_header);
return "$!table_header\n$underline\n\n$!body_content\n";
}
}
# as seen in Moose
my $instance = SomeObject->new(
table_header => "This is a header",
body_content => "Some body content",
);
$instance->body_content("Different content"); # set a member, as in Moose
print $instance->display;
# This is a header
# ================
#
# Different content
Although it has pretty syntax, don't use mop right now for serious projects and stick to Moose instead. If Moose is too heavyweight for you, then you might enjoy lighter alternatives like Mouse or Moo (these three object systems are mostly compatible with each other).
You are getting confused between hashes and hash references. You are also forgetting that the first parameter to any method is the object reference or the name of the package. Perl constructors are inherited like any other method, so you must bless the new object into the correct package for polymorphism to work properly. This code is what you intended
sub new {
my $package = shift;
my %self;
$self{table_header} = shift;
$self{body_content} = shift;
bless \%self, $package;
}
I am not clear what you mean by “directly reference the data member”, but if you hoped that you could avoid writing $self everywhere so that every variable was implicitly an element of the hash then you cannot. Perl is far more flexible than most languages, and can use any blessed reference as an object instance. It is most common to use a hash, but occasionally a reference to an array, a scalar, or even a file handle is more appropriate. The cost of this flexibility is specifying exactly when you are referring to a member of the blessed hash. I don't see that it's too great a burden.
You can always write your code more concisely. The method above can be written
sub new {
my $package = shift;
my %self;
#self{qw/ table_header body_content /} = #_;
bless \%self, $package;
}
Related
I'm a Java/C/C#/python coder who is attempting his first Perl script, and I have what is prob a Perl OOO 101 question: What is the syntax to access an object's members when use strict is required?
Let me speak Java for a moment. I have this little program, all in one class file:
class Dude{
public String name;
public Dude(String name){
this.name = name;
}
public void IntroduceYourself(){
System.out.println("Hi, I'm "+this.name);
}
}
public toy(){
Dude fred = new Dude("Fred");
fred.IntroduceYourself();
}
Output on my Ubuntu machine:
me#ubuntu01:~/$ java toy
Hi, I'm Fred
me#ubuntu01:~/$
What could be simpler? I create a Dude object, then later call method Dude.IntroduceYourself(), which accesses a class member.
Okay: I have to do the exact same thing, but now in Perl (v5.26.1). Again, use strict; is required. Here's my miserable attempt:
#!/usr/bin/perl
use warnings;
use strict;
# Define a "Dude" class
package Dude;
sub new
{
my $class = shift;
my $self = {
_name => shift,
};
bless $self, $class;
return $self;
}
sub IntroduceYourself
{
print("Hi, I'm $object->{name}\n"); # Compilation Error here!
}
my $object = new Dude("Fred");
$object->IntroduceYourself();
Output on the same Ubuntu machine:
me#ubuntu01:~/$ ./toyPerl.pl
Global symbol "$Dude" requires explicit package name (did you forget to declare "my $Dude"?) at ./toyPerl.pl line 18.
Execution of ./toyPerl.pl aborted due to compilation errors.
me#ubuntu01:~/$
Ugh. I've been reading a few Perl tutorials, and I see examples on how to write that IntroduceYourself() subroutine, but none with use strict as a global directive. Can anyone see what I'm doing wrong?
Also: I'm really confused about what I'll call "member functions" in Perl. In my Java example, Dude.IntroduceYourself() was defined as a method of class Dude. I intend (if possible) for IntroduceYourself() to be a function of Object/Class Dude in the Perl code. But its unclear to me how to define that. Am I misunderstanding how Perl objects handle member functions? Thank you.
This doesn't have to do with OO, just Perl's normal strict behavior. strict forces you to declare variables, like in other languages. Without strict, undeclared objects are globals. $object is never declared, so it violates strict.
To solve this, $object must be declared. Perl's this is passed in as the first argument to a method. You need to get that argument. Perl calls this the "invocant". Typically it is called $self.
What is the syntax to access an object's members
Perl doesn't have object members like Java. A Perl object is just a reference. It doesn't even need to be a hash reference. $self->{key} is just using a hash reference, so the key has to match. $self->{_name} not $self->{name}.
sub IntroduceYourself {
# Get the invocant off the list of arguments.
my $self = shift;
# Use it as a hash reference with the correct key.
print("Hi, I'm $self->{_name}\n");
}
I intend (if possible) for IntroduceYourself() to be a function of Object/Class Dude in the Perl code. But its unclear to me how to define that.
You did it. A class is just a package. A method is just a subroutine in a package. The language does not make a distinction between subroutines and methods, nor between class and object methods. It's just how you use them.
#!/usr/bin/perl
use strict;
use warnings;
package Foo {
sub new {
my $class = shift;
my($name) = #_;
return bless { name => $name }, $class;
}
sub hello {
my $self = shift;
print "Hello my name is $self->{name}\n";
}
}
my $foo = Foo->new("Pete");
# Called as an object method.
$foo->hello;
# Called as a subroutine.
# It works, but don't do it; it bypasses inheritance.
Foo::hello($foo);
# Called as a class method.
# It "works", but since the method expects $self to be a
# reference, not a package name, $self->{name} is... it's complicated.
Foo->hello;
Perl's OO is extremely basic. You get classes (via packages), multiple-inheritance (via #ISA), and methods (via subroutines with the invocant passed in) and that's about it. No accessors, no public, no private, no members, not even this.
If you want that, you have to write it yourself, or use an existing library. If you want all the bells and whistles and a full marching band, install Moose.
...use strict as a global directive...
use strict is not global, it is local to the current scope. The current scope is the whole file, but you can put it in a block.
{
# strict is on in this block
use strict;
my $foo = 42;
print "$foo\n";
}
# strict is off everywhere else
$bar = 23;
print "$bar\n";
Things like strict and warnings are referred to as "pragmas".
See "What's the difference between dynamic and lexical (static) scoping? Between local() and my()?".
sub IntroduceYourself {
my $self = shift;
print( "Hi, I'm $self->{ _name }\n" );
}
See perlootut.
In OOP, the invocant (the value of the expression before the ./->) is passed to the method as an argument. In Java, this argument is made available as this. In Perl, this argument is made available as a leading parameter.
This means that
$o->foo( $x, $y )
is equivalent to
my $method = $o->can( 'foo' );
$method->( $o, $x, $y )
And the method looks like this:
sub foo {
my $self = shift;
my $x = shift;
my $y = shift;
$self->{ x } = $x;
$self->{ y } = $y;
}
While following this tutorial
https://www.codeproject.com/Articles/3152/Perl-Object-Oriented-Programming
I am failing to see where module Address.pm is.. did I miss something or article has an error or do I have a misunderstanding when one of the module says ' use Address ';
mac1:moduleTEST1 user1$ ./Employee.pl
Can't locate object method "new" via package "Address" (perhaps you forgot to load "Address"?) at ./Employee.pl line 16.
mac1:moduleTEST1 user1$
The tutorial is outdated and rather useless. Specifically, it is much worse than the documentation which comes with Perl. Use perldoc perltoc to get a table of contents, and read everything at least once.
See perldoc perlootut and perldoc perlobj.
package Address;
use strict;
use warnings;
sub new {
my $class = shift;
my $args = shift;
my %self = map +($_ => $args->{$_}), qw( street city state zip );
bless \%self => $class;
}
sub street {
my $self = shift;
if ( #_ ) {
$self->{street} = $_[0];
return;
}
return $self->{street};
}
# ditto for the rest of the accessors # there are
# ways to cut down the boilerplate once you learn
# the basics
#
# ...
__PACKAGE__
__END__
You use this module like this:
my $address = Address->new({
street => '123 E. Any St',
city => 'Any Town',
state => 'AY',
zip => '98765',
});
Of course, there a lot of things missing from this little demo. For example, the accessor, as written, allows you to change the state of the object. Immutable objects are easier to reason about, so you might want to disallow that by changing it to:
sub street { $_[0]->{street} }
It also allows you to assign any value you want to fields like state and zip. So, you may want to validate those values in the constructor, ensure that only values for the fields of the class are passed, all the values passed are defined etc.
At the end of that process, you may decide it doesn't make sense to keep writing boilerplate and use Moo or Moose to avail yourself to a richer set of features.
Even then, it helps to know what's happening under the hood.
I have a class called Question, and a bunch of sub-classes depending on the type of question. I can create objects against the sub-classes, but I shouldn't be able to create an object of class Question itself:
#! /usr/bin/env perl
use strict;
use warnings;
#
# LOAD IN YOUR QUESTIONS HERE
#
my #list_of_questions;
for my $question_type qw(Science Math English Dumb) {
my $class = "Question::$question_type";
my $question = $class->new;
push #list_of_questions, $question;
}
package Question;
use Carp;
sub new {
my $class = shift;
my $self = {};
if ( $class = eq "Question" ) {
carp qq(Need to make object a sub-class of "Question");
return;
}
bless $self, $class;
return $self;
}
yadda, yadda, yadda...
package Question::Math;
use parent qw(Question);
yadda, yadda, yadda...
package Question::Science;
use parent qw(Question);
yadda, yadda, yadda...
package Question::English;
use parent qw(Question);
yadda, yadda, yadda...
Notice these are not modules, but merely classes I've defined to be used in my program. Thus, I can't test module loading at runtime.
When I run the above, I get:
Can't locate object method "new" via package "Question::Dumb" (perhaps you forgot to load "Question::Dumb"?)
Is there any way to catch for this particular error, so I can handle it myself? I know I could create an array of valid types, but I was hoping someway of being able to add new question type without having to remember to update my array.
AFAICT what you want to do is check the symbol table to see if your "class" (aka "package") has been defined or not. Doing it manually is no hardship, but Class::Load provides slightly more readable sugar and applies "heuristics" - whatever that means. If you don't want to use this module then the source code for is_class_loaded will lead you to whatever answer you're actually seeking.
use Class::Load qw(is_class_loaded);
for my $question_type (qw(Math English Science Dumb)) {
my $class = "Question::$question_type";
if(!is_class_loaded($class)) {
# construct your new package at runtime, then
}
new_question($class);
}
Your variable name ("class_type") was weird, so I fixed it. I also don't know whether Module::Load is better, but we use Class::Load for this at work.
Edit: bare qw()s are deprecated in one of the newer Perls (5.14?). It's a stupid deprecation, but it's there, so we all have to learn to wrap our qw() foreachs in parens now.
You can't have an expression like Invalid::Class->new() not throw an exception in the calling code, but you can wrap it in exception handling and wrap that inside a method. The standard pattern is to supply a 'type' argument describing the subclass you which to create to a factory method. A common anti-pattern is to put that factory method on the base class, creating a circular dependency and having to do more work than should be required.
It is usual to have the factory method on the interface class and to have it construct sub-classes of an unrelated, dedicated base class, possibly warning or throwing when it fails. In code, that looks pretty much like so:
package Question;
use Try::Tiny;
use Carp qw/carp/;
sub new {
my ($class, $type, #args) = #_;
# could do some munging on $type to make it a class name here
my $real_class = "Question::$type";
return try {
$real_class->new(#args);
} catch {
# could differentiate exception types here
carp qq(Invalid Question type "$type");
};
}
package Question::Base;
sub new {
my ($class) = #_;
return bless {} => $class;
}
package Question::Math;
use base 'Question::Base'; # `use parent` expects to load a module
package main;
use Test::More tests => 2;
use Test::Warn;
isa_ok(Question->new('Math'), 'Question::Math');
warning_like(
sub { Question->new('Dumb') }, # I hear there's no such thing
qr/^Invalid Question/
);
Here's what I finally did:
package Question;
use Carp;
sub new {
my $class = shift;
my %params = #_;
#
# Standardize the Parameters
# Remove the dash, double-dash in front of the parameter and
# lowercase the name. Thus, -Question, --question, and question
# are all the same parameter.
#
my %option_hash;
my $question_type;
for my $key (keys %params) {
my $value = $params{$key};
$key =~ s/^-*//; #Remove leading dashes
$key = ucfirst ( lc $key ); #Make Key look like Method Name
if ( $key eq "Type" ) {
$question_type = ucfirst (lc $value);
}
else {
$option_hash{$key} = $value;
}
}
if ( not defined $question_type ) {
carp qq(Parameter "type" required for creating a new question.);
return;
}
#
# The real "class" of this question includes the question type
#
my $self = {};
$class .= "::$question_type";
bless $self, $class;
#
# All _real does is return a _true_ value. This method is in this
# class, so all sub-classes automatically inherit it. If the eval
# fails, this isn't a subclass, or someone wrote their own `_real_
# method in their sub-class.
#
eval { $self->_real; };
if ( $# ) {
carp qq(Invalid question type of $question_type);
return;
}
#
# Everything looks good! Let's fill up our question object
#
for my $method ( keys %option_hash ) {
my $method_set;
eval { $method_set = $self->$method( $option_hash{$method} ) };
if ( $# or not $method_set ) {
carp qq(Can't set "$method" for question type "$question_type");
return;
}
}
return $self;
}
Now, I'm setting my question like this:
my $question = Question->new(
--type => Integer,
--question => "Pick a number between 1 and 10.",
--help => "Try using the top row of your keyboard...",
--from => "1",
--to => "10",
);
if ( not defined $question ) {
die qq(The question is invalid!);
}
Darch use of the Try::Tiny is nice. It looks way better than wrapping everything in an eval. Unfortunately, it's not a standard module. This program is going on almost 100 separate systems, and using CPAN modules is too difficult. This is especially true since these systems are behind a firewall and can't access the CPAN website.
I basically use Darch's method except I create a _real method in my super-class that I try after I bless the object. If it executes (that's all I really care), then this is a sub-class of my super-class.
This does what I really want: Hide my sub-classes behind my superclass -- much like File::Spec does. Most of my classes have the same methods, and a few have one or two extra methods. For example, my Regex question type has a Pattern method that allows me to make sure the answer given matches a given pattern.
I have the following problem, may be I am trying to solve it in a bad way so if you tell me how to do it in a right way I would be very grateful!
I have a base class which has a method which I want to access to a package variable based on real object class (ref($self)).
#!/usr/bin/env perl
my $var = SubClass->new();
$var->method();
package BaseClass;
sub new { construct... }
sub method {
my $self = shift;
# in this method I wan to get values from 'our %VAR' of the children class or ref($self) class, something like that:
return ${ref($self)::VAR}{k1};
# of course I can create a method and do it in the following way but I am not sure that it's a good idea
return $self->get_var()->{k1};
}
sub get_var { die "Imaplement in children"; }
package SubClass;
use base 'BaseClass';
our %VAR = (k1 => 'smth', k2 => 'smth', ...);
sub get_var { return \%VAR } # don't like this idea
1;
Using the %{ref($self)::VAR} solution may sometimes be the easiest, although a paranoid programmer would include some checks:
# Accessing %__PACKAGE__::VAR:
# I hope that I'm not in a subclass,
# because that would change the value reported by `ref($self)`
# and I can't be bothered to search #ISA manually...
unless (defined ref $self) {
die "\$self is not a reference!";
}
if (ref $self ~~ [qw/SCALAR ARRAY HASH
CODE REF GLOB LVALUE FORMAT IO VSTRING Regexp /]) {
die "\$self is not an object!";
}
no strict 'refs'; # Hehe, I can't use strict here :S
unless (%{ref($self).'::VAR'}) {
warn "Umm, this hash is empty."
. "I don't know if I just created it, or it is meant to be that way.";
}
return ${ref($self).'::VAR'}{k1};
In conclusion, using an accessor method does not only save us repetition, it is also safer, less hackish and far more object oriented:
sub return_var {
# We know that we are in the right package.
# We know we are accessing the correct hash.
# It is irrelevant whether I call this method
# from the package/class or from an object.
# And I'm glad to take the method performance penalty
# in exchange for clear code.
return \%VAR;
}
In conclusion #2, there is more than one way to do it. And in Perl, there is no "right" way. Although you might understand why I find the second solution more elegant.
My goal is to be able to use $obj like this:
print $obj->hello() . $obj->{foo};
And I would like to create an object inline, maybe using something like this:
my $obj = (
foo => 1,
hello => sub { return 'world' }
);
but when I try to use $obj as an object, I get an error saying that $obj has not been blessed. Is there some base class (like stdClass in PHP) I can use to bless the hash so that I can use it as an object?
For those that know JavaScript, I am trying to do the following, but in Perl:
# JS CODE BELOW
var obj = { foo: 1, hello: function () { return 'world' } };
echo obj.hello() + obj.foo;
Perl would require a little help to do this. Because it doesn't consider code references stored in hashes as "methods". Methods are implemented as entries into a package symbol table. Perl is more class-oriented than JavaScript, which proudly proclaims that it is more object-oriented (on individual objects).
In order to do that functionality, you would have to create a class that mapped references in this way. The way to get around methods in the symbol table is the AUTOLOAD method. If a package contains an AUTOLOAD subroutine, when a call is made to a blessed object that Perl cannot find in the inheritance chain, it will call AUTOLOAD and set the package-scoped (our) variable $AUTOLOAD will contain the full name of the function.
We get the name of the method called, by getting the last node (after the last '::') of the fully-qualified sub name. We look to see if there is a coderef at that location, and if there is, we can return it.
package AutoObject;
use strict;
use warnings;
use Carp;
use Params::Util qw<_CODE>;
our $AUTOLOAD;
sub AUTOLOAD {
my $method_name = substr( $AUTOLOAD, index( $AUTOLOAD, '::' ) + 2 );
my ( $self ) = #_;
my $meth = _CODE( $self->{$method_name} );
unless ( $meth ) {
Carp::croak( "object does not support method='$method_name'!" );
}
goto &$meth;
}
1;
Then you would bless the object into that class:
package main;
my $obj
= bless { foo => 1
, hello => sub { return 'world' }
}, 'AutoObject';
print $obj->hello();
Normally, in an AUTOLOAD sub I "cement" behavior. That is, I create entries into the package symbol table to avoid AUTOLOAD the next time. But that's usually for a reasonably defined class behavior.
I also designed a QuickClass which creates a package for each object declared, but that contains a lot of symbol table wrangling that now days is probably better done with Class::MOP.
Given the suggestion by Eric Strom, you could add the following code into the AutoObject package. The import sub would be called anytime somebody use-d AutoObject (with the parameter 'object').
# Definition:
sub object ($) { return bless $_[0], __PACKAGE__; };
sub import { # gets called when Perl reads 'use AutoObject;'
shift; # my name
return unless $_[0] eq 'object'; # object is it's only export
use Symbol;
*{ Symbol::qualify_to_reference( 'object', scalar caller()) }
= \&object
;
}
And then, when you wanted to create an "object literal", you could just do:
use AutoObject qw<object>;
And the expression would be:
object { foo => 1, hello => sub { return 'world' } };
You could even do:
object { name => 'World'
, hello => sub { return "Hello, $_[0]->{name}"; }
}->hello()
;
And you have an "object literal" expression. Perhaps the module would be better called Object::Literal.
A more Perlish approach is to create a separate namespace for your object's desired methods and to bless the object to make those methods available for your object. The code to do this can still be quite succint.
my $obj = bless { foo => 1 }, "bar";
sub bar::hello { return 'world' };
As gbacon suggests, if you're willing to write $obj->{hello}->() instead of $obj->hello(), you can skip the bless operation.
my $obj = { foo => 1, hello => sub { return 'world' } };
Try Hash::AsObject from CPAN.
In whatever function you're creating the object in, you need to call bless on your object in order to enable method calling.
For example:
package MyClass;
sub new
{
my $obj = {
foo => 1
};
return bless($obj, "MyClass");
}
sub hello
{
my $self = shift;
# Do stuff, including shifting off other arguments if needed
}
package main;
my $obj = MyClass::new();
print "Foo: " . $obj->{foo} . "\n";
$obj->hello();
EDIT: If you want to be able to use subroutine references to provide dynamic functionality for your objects...
First, you can create your code reference like so (within this hash constructor example):
my $obj = {
foo => 1,
hello => sub { print "Hello\n"; },
}
You can then invoke it like this:
my $obj = MyClass::new(); # or whatever
$obj->{hello}->(#myArguments);
A little cumbersome, but it works. (You might not even need the second arrow, but I'm not sure.)
$obj would be a scalar, so whatever you assign to it has to be a scalar as well. You could either say
my %obj = ( foo => 1, hello => sub { return 'world' });
or
my $obj = { foo => 1, hello => sub { return 'world' }};
The latter, with the curly braces, creates a hash reference (which is a scalar, so it can go into $obj). To get to the stuff inside a hash reference, though, you have to use the arrow operator. Something like $obj->{foo} or &{$obj->{hello}}.
Unless you need to have lists of hashes or something like that, it's generally better to use the first method.
Either way, you won't be able to say $obj->hello(). Perl uses that syntax for its own flavor of OOP, which would have the hello function in a separate package that your reference has been blessed into. Like:
package example;
sub new {} { my $result = {}; return bless $result, 'example' }
sub hello { return 'world' }
package main;
my $obj = example->new();
As you can see, the methods you can call are already defined, and it's not trivial to add more. There are magic methods you can use to do such a thing, but really, it's not worth it. &{$obj{hello}} (or &{$obj->{hello}} for a reference) is less effort than trying to make Perl work like Javascript.
It's spelled a little bit differently in Perl:
my $obj = { foo => 1, hello => sub { return "world" } };
print $obj->{hello}() . $obj->{foo};
But the code is awkward. The warning you saw about the reference not being blessed is telling you that your objects aren't implemented in the way Perl expects. The bless operator marks an object with the package in which to begin searching for its methods.
Tell us what you want to do in terms of your problem domain, and we can offer suggestions for a more natural approach in Perl.
Methods in Perl are not properties of the object like they are in Python. Methods are plain regular functions functions in a package associated with the object. Regular functions taking an extra argument for the self reference.
You cannot have dynamically created functions as methods.
Here is a quote from perldoc perlobj:
1. An object is simply a reference that happens to know which class it
belongs to.
2. A class is simply a package that happens to provide methods to deal
with object references.
3. A method is simply a subroutine that expects an object reference
(or a package name, for class methods) as the first argument.
Oh, and bless() is how you establish the connection between the reference and the package.
I recommend using Class::Struct as explained in perltoot man page.
Instead of paraphrasing the documentation, let me quote it as it explained well how this works:
"What it does is provide you a way to "declare" a class as having objects whose fields are of a specific type. The function that does this is called, not surprisingly enough, struct(). Because structures or records are not base types in Perl, each time you want to create a class to provide a record-like data object, you yourself have to define a new() method, plus separate data-access methods for each of that record's fields. You'll quickly become bored with this process. The Class::Struct::struct() function alleviates this tedium."
Still quoting from the doc is an example way on how to implement it:
use Class::Struct qw(struct);
use Jobbie; # user-defined; see below
struct 'Fred' => {
one => '$',
many => '#',
profession => 'Jobbie', # does not call Jobbie->new()
};
$ob = Fred->new(profession => Jobbie->new());
$ob->one("hmmmm");
$ob->many(0, "here");
$ob->many(1, "you");
$ob->many(2, "go");
print "Just set: ", $ob->many(2), "\n";
$ob->profession->salary(10_000);