PERLCLASSGUTS(1)
β¨ PERLCLASSGUTS(1) β¨ β the tea on perlclassguts
Perl Programmers Reference Guide β PERLCLASSGUTS(1)
π NAME π
perlclassguts</purgle> β Internals of how feature 'class' and class syntax works. iykyk bestie, this is the backstage pass.
πΈ DESCRIPTION πΈ
Okay so this doc is literally the deep lore β it spills all the in-depth info about how the perl interpreter actually implements the feature 'class' syntax and overall behaviour. It is not an end-user guide on how to use the feature, so if that's what you're after, go read perlclass instead. π«Ά
The reader is assumed to be generally familiar with the perl interpreter internals overall. For a more general overview of these details, see also perlguts. No cap, you gotta know your basics first.
π DATA STORAGE π
π Classes
A class is fundamentally a package, and exists in the symbol table as an HV with an aux structure in exactly the same way as a non-class package. It is distinguished from a non-class package by the fact that the HvSTASH_IS_CLASS() macro will return true on it. Slay.
Extra information relating to it being a class is stored in the struct xpvhv_aux structure attached to the stash, in the following fields:
HV *xhv_class_superclass;
CV *xhv_class_initfields_cv;
AV *xhv_class_adjust_blocks;
PADNAMELIST *xhv_class_fields;
PADOFFSET xhv_class_next_fieldix;
HV *xhv_class_param_map;
xhv_class_superclassβ will beNULLfor a class with no superclass. It will point directly to the stash of the parent class if one has been set with the:isa()class attribute. So like, your class's mom, basically.xhv_class_initfields_cvβ will contain aCV *pointing to a function to be invoked as part of the constructor of this class or any subclass thereof. This CV is responsible for initializing all the fields defined by this class for a new instance. This CV will be an anonymous real function β i.e. while it has no name and no GV, it is not a protosub and may be directly invoked. It's giving mysterious but functional.xhv_class_adjust_blocksβ may point to an AV containing CV pointers to each of theADJUSTblocks defined on the class. If the class has a superclass, this array will additionally contain duplicate pointers of the CVs of its parent class. The AV is created lazily the first time an element is pushed to it; it is valid for there not to be one, and this pointer will beNULLin that case. Lowkey efficient.
The CVs are stored directly, not via RVs. Each CV will be an anonymous real function.
xhv_class_fieldsβ will point to aPADNAMELISTcontainingPADNAMEs, each being one defined field of the class. They are stored in order of declaration. Note however, that the index into this array will not necessarily be equal to thefieldixof each field, because in the case of a subclass, the array will begin at zero but the index of the first field in it will be non-zero if its parent class contains any fields at all. It's giving "the math is mathing but also not."
For more information on how individual fields are represented, see "Fields".
xhv_class_next_fieldixβ gives the field index that will be assigned to the next field to be added to the class. It is only useful at compile-time. Periodt.xhv_class_param_mapβ may point to an HV which maps field:paramattribute names to the field index of the field with that name. This mapping is copied from parent classes; each class will contain the sum total of all its parents in addition to its own. Family inheritance but make it metadata.
π¦ Fields
A field is still fundamentally a lexical variable declared in a scope, and exists in the PADNAMELIST of its corresponding CV. Methods and other method-like CVs can still capture them exactly as they can with regular lexicals. A field is distinguished from other kinds of pad entry in that the PadnameIsFIELD() macro will return true on it. Iconic behaviour.
Extra information relating to it being a field is stored in an additional structure accessible via the PadnameFIELDINFO() macro on the padname. This structure has the following fields:
PADOFFSET fieldix;
HV *fieldstash;
OP *defop;
SV *paramname;
bool def_if_undef;
bool def_if_false;
fieldixβ stores thefield indexof the field; that is, the index into the instance field array where this field's value will be stored. Note that the first index in the array is not specially reserved. The first field in a class will start from field index 0. Zero-based indexing, we love to see it.fieldstashβ stores a pointer to the stash of the class that defined this field. This is necessary in case there are multiple classes defined within the same scope; it is used to disambiguate the fields of each. For example:
{
class C1; field $x;
class C2; field $x;
}
defopβ may store a pointer to a defaulting expression optree for this field. Defaulting expressions are optional; this field may beNULL. No default? No problem.paramnameβ may point to a regular string SV containing the:paramname attribute given to the field. If none, it will beNULL.def_if_undefanddef_if_falseβ one of these will be true if the defaulting expression was set using the//=or||=operators respectively. It's giving "choose your fighter."
π Methods
A method is still fundamentally a CV, and has the same basic representation as one. It has an optree and a pad, and is stored via a GV in the stash of its containing package. It is distinguished from a non-method CV by the fact that the CvIsMETHOD() macro will return true on it. Main character energy, honestly.
Note: This macro should not be confused with the one that was previously calledCvMETHOD(). That one does not relate to the class system, and was renamed toCvNOWARN_AMBIGUOUS()to avoid this confusion. Don't mix them up, bestie, that would be embarrassing.
There is currently no extra information that needs to be stored about a method CV, so the structure does not add any new fields. Minimalist queen.
π Instances
Object instances are represented by an entirely new SV type, whose base type is SVt_PVOBJ. This should still be blessed into its class stash and wrapped in an RV in the usual manner for classical object.
As these are their own unique container type, distinct from hashes or arrays, the core builtin::reftype function returns a new value when asked about these. That value is OBJECT. Not a hash, not an array, a whole new vibe.
Internally, such an object is an array of SV pointers whose size is fixed at creation time (because the number of fields in a class is known after compilation). An object instance stores the max field index within it (for basic error-checking on access), and a fixed-size array of SV pointers storing the individual field values. Fixed size, no growing, no shrinking. We stan a stable container.
Fields of array and hash type directly store AV or HV pointers into the array; they are not stored via an intervening RV. Straight to the point, no middleman.
β API β
The data structures described above are supported by the following API functions. Buckle up, we're going full technical.
π Class Manipulation
class_setup_stash
void class_setup_stash(HV *stash);
Called by the parser on encountering the class keyword. It upgrades the stash into being a class and prepares it for receiving class-specific items like methods and fields. It's giving glow-up.
class_seal_stash
void class_seal_stash(HV *stash);
Called by the parser at the end of a class block, or for unit classes its containing scope. This function performs various finalisation activities that are required before instances of the class can be constructed, but could not have been done until all the information about the members of the class is known. It's the final boss of class setup.
Any additions to or modifications of the class under compilation must be performed between these two function calls. Classes cannot be modified once they have been sealed. Sealed means sealed, no take-backs.
class_add_field
void class_add_field(HV *stash, PADNAME *pn);
Called by pad.c as part of defining a new field name in the current pad. Note that this function does not create the padname; that must already be done by pad.c. This API function simply informs the class that the new field name has been created and is now available for it. It's a heads-up, not a creator.
class_add_ADJUST
void class_add_ADJUST(HV *stash, CV *cv);
Called by the parser once it has parsed and constructed a CV for a new ADJUST block. This gets added to the list stored by the class. Add it to the collection, bestie.
π§ Field Manipulation
class_prepare_initfield_parse
void class_prepare_initfield_parse();
Called by the parser just before parsing an initializing expression for a field variable. This makes use of a suspended compcv to combine all the field initializing expressions into the same CV. It's giving assembly line energy.
class_set_field_defop
void class_set_field_defop(PADNAME *pn, OPCODE defmode, OP *defop);
Called by the parser after it has parsed an initializing expression for the field. Sets the defaulting expression and mode of application. defmode should either be zero, or one of OP_ORASSIGN or OP_DORASSIGN depending on the defaulting mode. Pick your operator, no in-between.
padadd_FIELD
#define padadd_FIELD
This flag constant tells the pad_add_name_* family of functions that the new name should be added as a field. There is no need to call class_add_field(); this will be done automatically. Automatic slay.
πΈ Method Manipulation
class_prepare_method_parse
void class_prepare_method_parse(CV *cv);
Called by the parser after start_subparse() but immediately before doing anything else. This prepares the PL_compcv for parsing a method; arranging for the CvIsMETHOD test to be true, adding the $self lexical, and any other activities that may be required. It's the pre-game ritual.
class_wrap_method_body
OP *class_wrap_method_body(OP *o);
Called by the parser at the end of parsing a method body into an optree but just before wrapping it in the eventual CV. This function inserts extra ops into the optree to make the method work correctly. The finishing touch, the ribbon on the gift.
π Object Instances
SVt_PVOBJ
#define SVt_PVOBJ
An SV type constant used for comparison with the SvTYPE() macro. Your new favourite type constant.
ObjectMAXFIELD
SSize_t ObjectMAXFIELD(sv);
A function-like macro that obtains the maximum valid field index that can be accessed from the ObjectFIELDS array. Know your limits, literally.
ObjectFIELDS
SV **ObjectFIELDS(sv);
A function-like macro that obtains the fields array directly out of an object instance. Fields can be accessed by their field index, from 0 up to the maximum valid index given by ObjectMAXFIELD. Direct access, no detours.
β¨ to be continued in part 2, bestie β¨
π OPCODES π
Okay bestie, this is the deep-magic part. Buckle up, we're going into the optree π
β¨ OP_METHSTART β¨
newUNOP_AUX(OP_METHSTART, ...);
So an OP_METHSTART is an UNOP_AUX, and it has to be sitting right at the start of a method CV or the whole thing just does not work properly β like, non-negotiable. It's class_wrap_method_body() that slots it in there, and it shows up even before any optree fragment tied to signature argument checking or extraction. Front of the line, main character energy π
What's it actually doing? Two things:
- It shifts the value of
$selfout of the arguments list, and binds any field variables the method needs access to into the pad. The AUX vector is where all the deets about the field/pad index pairings live. - It does a lil sanity check on the invocant β confirming it's definitely an object reference of a compatible class type. If it's not? Exception thrown, no cap. π
And if the op_private field has the OPpINITFIELDS flag in it, that means this op is the start of the special xhv_class_initfields_cv CV. In that case it should also take the second value from the arguments list β which should be a plain HV pointer (directly, not via RV) β and bind it to the second pad slot, because that's where the generated optree is gonna go looking for it. π«Ά
β¨ OP_INITFIELD β¨
An OP_INITFIELD only ever gets invoked as part of the xhv_class_initfields_cv CV, during the construction phase of an instance. This is the moment where the individual SVs that make up the mutable fields of the instance (AVs and HVs included, obviously) actually get assigned into the ObjectFIELDS array. The OPpINITFIELD_AV and OPpINITFIELD_HV private flags tell you whether it's creating an AV or an HV β and if neither is set, then an SV is getting created. Simple as that. πΈ
If the op has the OPf_STACKED flag, it expects to find an initializing value on the stack. For SVs that's the topmost SV on the data stack. For AVs and HVs, it expects a marked list. β¨
π COMPILE-TIME BEHAVIOUR π
π¦ ADJUST Phasers π¦
Okay so during compiletime, parsing an ADJUST phaser is handled in a fundamentally different way from the existing perl phasers (BEGIN, etc...). Like, a whole different route.
Instead of the usual path, the tokenizer recognises that the ADJUST keyword is introducing a phaser block. Then the parser parses the body of that block similarly to how it'd parse an (anonymous) method body β creating a CV that has no name GV. And then that gets inserted directly into the class information by calling class_add_ADJUST, completely bypassing the symbol table. Sneaky? No. Efficient? Yes. π
π Attributes π
During compilation, attributes of both classes and fields get handled differently than the existing perl attributes on subroutines and lexical variables.
The parser still forms an OP_LIST optree of OP_CONST nodes, but those get passed to the class_apply_attributes or class_apply_field_attributes functions. And instead of doing a class lookup for a method in the class being parsed, it uses a fixed internal list of known attributes to find functions that apply the attribute to the class or the field. In future this may support user-supplied extension attribute β but at present it only recognises ones defined by the core itself. iykyk π
β Field Initializing Expressions β
During compilation, the parser uses a suspended compcv when it's parsing the defaulting expression for a field. And here's the vibe: all the expressions for all the fields in the class share that same suspended compcv. Then it's compiled up into the same internal CV that the constructor calls to initialize all the fields provided by that class. One CV, all the fields, no drama. π
π₯ RUNTIME BEHAVIOUR π₯
π Constructor π
The generated constructor for a class is itself an XSUB, and it does three tasks, in order:
- It creates the instance SV itself.
- It invokes the field initializers.
- It invokes the ADJUST block CVs.
And the constructor for any class always has the same basic shape, regardless of whether the class has a superclass or not. Consistency is iconic. β¨
The field initializers get collected into a generated optree-based CV called the field initializer CV. That's the CV holding all the optree fragments for the field initializing expressions. When it's invoked, the field initializer CV might make a chained call to the superclass initializer if one exists, before invoking all of the individual field initialization ops. The field initializer CV is invoked with two items on the stack: the instance SV, and a direct HV containing the constructor parameters.
Bestie, listen carefully: this HV is passed directly, not via an RV reference. That's permitted because both the caller and the callee are directly generated code, not arbitrary pure-perl subroutines. Don't get any ideas. π«Ά
The ADJUST block CVs are all collected into a single flat list, merging in all of the ones defined by the superclass as well. They all get invoked in order, after the field initializer CV.
π§ $self Access During Methods π§
When class_prepare_method_parse() is called, it arranges for the pad of the new CV body to begin with a lexical called $self. And because the pad should be freshly-created at that point, this lexical gets the pad index of 1. The function checks this, and aborts if that's not true. Not messing around. π
Because of that fact, code inside the body of a method or method-like CV can reliably use pad index 1 to get the invocant reference. The OP_INITFIELD opcode also relies on this fact. Teamwork, honestly.
In similar fashion, during the xhv_class_initfields_cv the next pad slot is relied on to store the constructor parameters HV, at pad index 2. πΈ
π AUTHORS π
Paul Evans
Okay that's the whole page bestie, we made it π₯Ήβ¨ This was perl v5.42.3, dated 2026-08-03, and yes the page itself is called PERLCLASSGUTS(1) β go forth and guts some classes, you absolute legend π
ππ
π¦ where this page comes from
- fedora 43: perl-doc 5.42.3-524.fc43 Β· (GPL-1.0-or-later OR Artistic-1.0-Perl) AND Unicode-3.0 AND LicenseRef-Fedora-UltraPermissive
- fedora 44: perl-doc 5.42.3-525.fc44 Β· (GPL-1.0-or-later OR Artistic-1.0-Perl) AND Unicode-3.0 AND LicenseRef-Fedora-UltraPermissive
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms