=head1 NAME
Class::Slot - Simple, efficient, comple-time class declaration
=head1 SYNOPSIS
package Point;
use Class::Slot;
use Types::Standard -types;
slot x => Int, rw => 1, req => 1;
slot y => Int, rw => 1, req => 1;
slot z => Int, rw => 1, def => 0;
1;
my $p = Point->new(x => 10, y => 20);
$p->x(30); # x is set to 30
$p->y; # 20
$p->z; # 0
=head1 DESCRIPTION
Similar to the L<fields> pragma, C<slot> declares individual fields in a
class, building a constructor and slot accessor methods.
Although not nearly as full-featured as L<other|Moose> L<solutions|Moo>,
C<Class::Slot> is light-weight, fast, works with basic Perl objects, and
imposes no dependencies outside of the Perl core distribution. Currently, only
the unit tests require non-core packages.
C<Class::Slot> is intended for use with Perl's bare metal objects. It provides
a simple mechanism for building accessor and constructor code at compile time.
It does I<not> provide inheritance; that is done by setting C<@ISA> or via the
C<base> or C<parent> pragmas.
It does I<not> provide method wrappers; that is done with the C<SUPER>
pseudo-class.
It I<does> build a constructor method, C<new>, with support for default and
required slots as keyword arguments and type validation of caller-supplied
values.
It I<does> build accesor methods (reader or combined reader/writer, using the
slot's name) for each slot declared, with support for type validation.
=head1 @SLOTS
The C<@SLOTS> package variable is added to the declaring package and is a list
of quoted slot identifiers. C<@SLOTS> includes I<all> slots available to this
class, including those defined in its ancestors.
=head1 CONSTRUCTOR
C<Class::Slot> generates a constructor method named C<new>. If there is already
an existing method with that name, it may be overwritten, depending on the
order of execution.
=head1 DECLARING SLOTS
The pragma itself accepts two positional parameters: the slot name and optional
type. The type is validated during construction and in the setter, if the slot
is read-write.
Slot names must be valid perl identifiers suitable for subroutine names. Types
must be either a code ref which returns true for valid values or an instance of
a class that supports the C<can_be_inlined>, C<inline_check>, and C<check>
methods (see L<Type::Tiny/Inlining methods>).
The C<slot> pragma may be used as either a keyword or a pragma. The following
are equivalent:
use Class::Slot x => Int;
use slot x => Int;
slot x => Int;
A simple source filter is used to translate uses of C<slot> and C<use slot>
into C<use Class::Slot>.
=head1 OPTIONS
=head2 rw
When true, the accessor method accepts a single parameter to modify the slot
value. If the slot declares a type, the accessor will croak if the new value
does not validate.
=head2 req
When true, this constructor will croak if the slot is missing from the named
parameters passed to the constructor. If the slot also declares a
L<default|/def> value, this attribute is moot.
=head2 def
When present, this value or code ref which returns a value is used as the
default if the slot is missing from the named parameters passed to the
constructor.
If the default is a code ref which generates a value and a type is specified,
note that the code ref will be called during compilation to validate its type
rather than re-validating it with every accessor call.
=head1 INHERITANCE
When a class declares a slot which is also declared in the parent class, the
parent class' settings are overridden. Any options I<not> included in the
overriding class' slot declaration remain in effect in the child class.
package A;
use Class::Slot;
slot 'foo', rw => 1;
slot 'bar', req => 1, rw => 1;
1;
package B;
use Class::Slot;
use parent -norequire, 'A';
slot 'foo', req => 1; # B->foo is req, inherits rw
slot 'bar', rw => 0; # B->bar inherits req, but is no longer rw
1;
=head1 COMPILATION PHASES
=head2 BEGIN
C<slot> statements are evaluated by the perl interpreter at the earliest
possible moment. At this time, C<Class::Slot> is still gathering slot
declarations and the class is not fully assembled.
=head2 CHECK
All slots are assumed to be declared by the C<CHECK> phase. The first slot
declaration adds a C<CHECK> block to the package that installs all generated
accessor methods in the declaring class. This may additionally trigger any
parent classes (identified by C<@ISA>) which are not yet complete.
=head2 RUNTIME
If C<CHECK> is not available (for example, because the class was generated in a
string eval), the generated code will be evaluated at run-time the first time
the class' C<new> method is called.
=head1 DEBUGGING
Adding C<use Class::Slot -debug> to your class will cause C<Class::Slot> to
print the generated constructor and accessor code just before it is evaluated.
Adding C<use Class::Slot -debugall> anywhere will cause C<Class::Slot> to emit
debug messages globally.
These may be set from the shell with the C<CLASS_SLOT_DEBUG> environmental
variable.
=head1 PERFORMANCE
C<Class::Slot> is designed to be fast and have a low overhead. When available,
L<Class::XSAccessor> is used to generate the class accessors. This applies to
slots that are not writable or are writable but have no declared type.
This behavior can be disabled by setting C<$Class::Slot::XS> to a negative
value, although this must be done in a C<BEGIN> block before declaring any
slots, or by setting the environmental variable C<CLASS_SLOT_NO_XS> to a
positive value before running.
A minimal benchmark on my admittedly underpowered system compares L<Moose>,
L<Moo>, and L<Class::Slot>. The test includes multiple setters using a mix of
inherited, typed and untyped, attributes, which ammortizes the benefit of
Class::XSAccessor to L<Moo> and L<Class::Slot>.
| Rate moo moose slot
| moo 355872/s -- -51% -63%
| moose 719424/s 102% -- -25%
| slot 961538/s 170% 34% --
Oddly, L<Moo> seemed to perform better running the same test without
L<Class::XSAccessor> installed.
| Rate moo moose slot
| moo 377358/s -- -50% -56%
| moose 757576/s 101% -- -12%
| slot 862069/s 128% 14% --
=head1 AUTHOR
Jeff Ober <
[email protected]>
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2018 by Jeff Ober.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.