=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 <sysread@fastmail.fm> =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.