Object::PadX::Enum - syntactic sugar for enum-like singleton-bearing Object::Pad classes
use Object::PadX::Enum;
enum Raptor {
item VELOCIRAPTOR ( max_speed_kmh => 60, max_weight_kg => 15, max_height_cm => 50 );
item DEINONYCHUS ( max_speed_kmh => 50, max_weight_kg => 80, max_height_cm => 87 );
item UTAHRAPTOR ( max_speed_kmh => 35, max_weight_kg => 500, max_height_cm => 150 );
item MICRORAPTOR ( max_speed_kmh => 40, max_weight_kg => 1, max_height_cm => 30 );
item DROMAEOSAURUS ( max_speed_kmh => 60, max_weight_kg => 15, max_height_cm => 50 );
field $max_speed_kmh :param :reader;
field $max_weight_kg :param :reader;
field $max_height_cm :param :reader;
method speed_per_kg { return $max_speed_kmh / $max_weight_kg }
method speed_per_cm { return $max_speed_kmh / $max_height_cm }
method fastest :common {
my ( $top ) = sort { $b->max_speed_kmh <=> $a->max_speed_kmh } $class->values;
return $top;
}
}
say Raptor->VELOCIRAPTOR->max_speed_kmh; # 60
say Raptor->DEINONYCHUS->speed_per_kg; # 0.625
say Raptor->from_ordinal(2)->name; # UTAHRAPTOR
say Raptor->from_name("MICRORAPTOR")->speed_per_cm; # 1.33333333333333
say 'Fastest in absolute terms: ', Raptor->fastest->name; # VELOCIRAPTOR or DROMAEOSAURUS (tie)Object::PadX::Enum adds two keywords on top of Object::Pad:
-
enum NAME ATTRS? { ... }Declares a class (using Object::Pad's
classmachinery) and auto-injects$ordinal :readerandname :readerfields. Thenamereader returns the identifier under which the singleton was declared (e.g."RED"). Inside the block, all normalObject::Padconstructs (field,method,ADJUST, ...) are available, plus theitemkeyword.The entire block body is executed while it is being compiled, BEGIN-block style; see "COMPILE-TIME SEMANTICS".
The following class-level attributes are accepted:
-
:isa(CLASS),:isa(CLASS VERSION) -
:extends(CLASS),:extends(CLASS VERSION)Declares a superclass; equivalent to Object::Pad's
:isa. The package is loaded automatically. If a VERSION is given,CLASS->VERSION(VERSION)is called to enforce it.An
enummay inherit from anotherenum. Fields, methods, roles andADJUSTphasers from the parent are inherited normally. The parent's items are not inherited: the child has its own ordinal-zero-based item sequence, and accessing a parent item name on the child raises an error. The child'svalues,from_ordinalandfrom_namesee only the child's items. A parent enum must be declared before a child enum that inherits from it; since enums are finalized while they are compiled, normal source ordering anduseordering satisfies this. -
:does(ROLE),:does(ROLE VERSION)Composes a role into the enum class. May be repeated for multiple roles. The role package is loaded automatically.
The class attributes
:abstract,:strict,:reprand:lexical_neware not supported.:abstractis semantically incompatible withitem(singletons cannot be constructed for an abstract class); the others have no public Object::Pad::MOP::Class entry point and would require reaching into private Object::Pad internals. -
-
item NAME ( ARGS );Declares a named singleton instance of the enclosing
enum.ARGSis the key/value list passed to the auto-generated constructor; the parentheses (and the arg list) are optional, soitem FOO;is equivalent toitem FOO();.ARGSis evaluated at compile time and therefore must not depend on runtime state; see "COMPILE-TIME SEMANTICS".
After the enum block closes, the following class-level methods are
installed on the enum class for each declared singleton NAME:
$singleton = ClassName->NAME; # the named singleton
@all = ClassName->values; # all singletons in declaration order
$byord = ClassName->from_ordinal(0);
$byname = ClassName->from_name("RED");The per-item accessors are installed as inlinable constant subs (of the kind
created by constant), so a function-style call such as
ClassName::NAME() is folded to a constant at the caller's compile
time. Method-call syntax ClassName->NAME dispatches through the same
sub and returns the same singleton.
Direct construction via ClassName->new(...) is blocked after the
enum block closes; the only ways to obtain a singleton are the per-item
accessor, from_name, and from_ordinal. Subclasses (whether plain
class or another enum) may still call new on themselves; the block
applies only to direct invocation on the enum class itself.
Enums are static, fixed sets of values, and the implementation treats them
that way: the whole enum block body is executed while it is being
compiled, much like a BEGIN block. In particular:
- The singletons are constructed, and all accessors installed, as soon as the
closing brace of the
enumblock has been parsed. They are visible from any code compiled afterwards, includingBEGINblocks later in the same file. itemargs are ordinary Perl expressions, but they are evaluated at compile time. An expression referencing runtime state (for example a lexical assigned during normal runtime) sees the value that variable has at compile time, usuallyundef. Use only compile-time-computable expressions initemargs.- Any other plain statements written inside the block also run at compile time.
Because construction happens at compile time, values derived from item args
can be precomputed once per singleton instead of recomputed on every call.
Assign them to a field in an ADJUST block:
enum Raptor {
item VELOCIRAPTOR ( max_speed_kmh => 60, max_weight_kg => 15 );
field $max_speed_kmh :param :reader;
field $max_weight_kg :param :reader;
field $speed_per_kg :reader;
ADJUST { $speed_per_kg = $max_speed_kmh / $max_weight_kg }
}Raptor->VELOCIRAPTOR->speed_per_kg then returns a value computed once,
at compile time, through a plain generated reader instead of a computing
method.
- User
fields require explicit:paramif you intend to set them viaitemargs.Object::PadX::Enumdoes not inject:paramautomatically. - The
enumblock body executes at compile time, soitemargs (and any other statements inside the block) must not depend on runtime state. See "COMPILE-TIME SEMANTICS". enum-level:abstract,:strict,:reprand:lexical_neware not supported. See the description of theenumkeyword above for the rationale;:isaand:doesare supported.- The names
values,from_ordinal,from_name,ordinalandnameare reserved and must not be used asitemnames.