PDD 17: Polymorphic Containers

Abstract

This PDD describes the internal structure and behavior of the Polymorphic Container (PMC) data type.

Description

PMCs implement all internal data types more complex than a simple integer, float, or string, and also the data types of high-level languages. Nothing outside the core of Parrot (in fact, nothing outside the data type's vtable routines) should infer anything about a PMC.

This does mean, though, that you need to either know what functions are available and what they do, or have some method of finding out. Parrot defines a standard set of functions that each PMC provides. More complex features are constructed out of these fundamental building blocks.

- PMCs contain both state and behavior
- PMCs can inherit from other PMCs
- PMCs can be composed of low-level roles
- High-level objects can subclass low-level PMCs

Implementation

Internal structure

All PMCs have the form:

    struct PMC {
        Parrot_UInt flags;
        VTABLE *vtable;
        DPOINTER *data;
        PMC *_metadata;
    }

flags holds a set of flags associated with the PMC; these are documented in include/parrot/pobj.h, and are generally only used within the Parrot internals.

vtable holds a pointer to the vtable associated with the PMC. This points to a set of functions, with interfaces described in "Vtable Functions" that implement the basic behaviour of the PMC (i.e. how it behaves under addition, subtraction, cloning etc.)

data holds a pointer to the core data associated with the PMC. This may be null.

_metadata holds internal PMC metadata (properties). See the setprop/getprop ops in docs/ops/pmc.pod.

_synchronize is for access synchronization between shared PMCs.

PMCs are used to implement the basic data types of the high level languages running on top of Parrot. For instance, a Perl 5 SV will map onto one (or more) types of PMC, while particular Python datatypes will map onto different types of PMC.

Defining PMCs

PMCs are declared by the pmclass keyword:

  pmclass <name> [ <modifier> ... ] {
  }

The modifiers specify core features, such as:

abstract
The PMC cannot be instantiated. (By convention, abstract classes are given lower-case names.)
no_init
Don't generate class initialization code (don't set up a vtable for the PMC). Used with abstract.
dynpmc
The PMC is a dynamic PMC, so generate special class initialization code suitable for dynamic loading at runtime.
singleton
The PMC is a singleton, created in the constant PMC pool.
no_ro
Don't create a second read-only vtable for the PMC. (Used, for example, by STM's share_ro().)
is_shared
The PMC is shared (across threads).
extends
Inherit from another PMC. Takes one argument, the name of the PMC to inherit from.
does
Compose a role. Takes one argument, the name of the role to compose. [NOTE: this modifier has been taken from the older feature does which is now called provides.]
resolves
Resolve a conflicting vtable function, method, or attribute from a composed role by using the same named vtable function, method, or attribute from the current pmclass or prole.
provides
The PMC satisfies a particular low-level interface, which gives some assurances on how and where a PMC can be used.Roles composed with does may also define provides for one or more interfaces. (They generally define at least a provides corresponding to their own name.)
  • array is an aggregate PMC with numerically-keyed elements
  • hash is an aggregate PMC with string-keyed elements
  • library corresponds to a dynamic library
  • ref references another PMC
  • string behaves similarly to the base string type
  • integer behaves similarly to the base int type
  • float behaves similarly to the base number type
  • boolean does true/false only.
  • scalar (only used by the sample src/dynpmc/foo.pmc)
  • event can be used with event queue
hll
Declare the PMC in an HLL namespace other than the default HLL 'parrot'. Takes one argument, the name of the HLL.
maps
Map the current PMC to a core PMC type for code declared in a particular HLL. May only be used together with the hll modifier.

Defining attributes

The attributes of a PMC (both public and private) live in a custom struct for the PMC, stored in the data member of the PMC struct. The standard way of declaring attributes is with ATTR within the body of a pmclass or prole declaration.

  ATTR <type> <name> [ :<modifier> ... ];

This declaration is used to generate the data struct for the PMC (named "Parrot_<pmcname>_attributes"). The data struct incorporates any attributes declared in a composed role or inherited class. Composed attributes are inserted at the end of the generated struct. Inherited attributes are inserted at the top of the generated struct, so the struct members shared by the parent and child are in the same position, and code compiled for direct struct access to the parent can also perform the same direct struct access on the child.

The declaration is also used to generate accessor macros, GET_ATTR_attrname and SET_ATTR_attrname, to set up helper information for the inspect vtable function, and to provide attribute access through the default get_attr and set_attr vtable functions.

It's also possible to define and store the PMC's data struct manually, but the standard declaration syntax must be used in roles, in PMCs that compose roles, and in PMCs that will be subclassed by high-level classes (this means all core PMCs, and most non-core PMCs).

Low-level PMCs that use multiple inheritance (pmclass declarations with more than one extends entry) have to be careful with the contents of their structs. There's no problem if the two parents have identical data struct members. But, if the two parents have different data struct members, any vtable functions inherited from the parents will not be able to directly access the parents' struct members or use the accessor macros. The solution is to either override those vtable functions that directly access data struct members in the child PMC, define the parents as roles instead of classes, or declare the multiply inheriting child in PIR or an HLL.

Defining vtable functions

Vtable functions are defined as C functions within the body of the pmclass declaration, and are marked with VTABLE.

  VTABLE STRING *get_string() {...}
  VTABLE void set_string_native(STRING *value) {...}

Within the body of vtable functions, several shortcuts are provided:

INTERP
The current interpreter object.
SELF
The current invocant by dynamic type.
STATICSELF
The current invocant by static type.
SUPER
Calls the current method in the nearest superclass, using the dynamic type of SELF.
STATICSUPER
Calls the current method in the nearest superclass, using the static type of SELF.

Methods

Methods are declared in the body of the pmclass or prole declaration with METHOD.

  METHOD inspect(STRING *what :optional, int got_what :opt_flag) {...}

PMCs and Namespaces

Like high-level classes, low-level PMCs are tied to a corresponding namespace. By default this is a namespace with the same name as the PMC in the 'parrot' HLL, but the hll modifier in the pmclass declaration selects a different HLL.

Accessing a core PMC type from within an HLL other than 'parrot' requires the same steps as accessing a class from another HLL, first retrieving the namespace object, and then instantiating from that namespace.

  $P0 = get_root_namespace ['parrot'; 'Integer']
  $P1 = new $P0

HLLs can choose to provide direct access to Parrot's core PMC types by aliasing them within the HLL namespace.

Inheritance

PMCs can inherit behavior and state from other PMCs. Inheritance is performed in the pmclass declaration using the extends keyword.

  pmclass Foo extends Bar {
  }

Composition

Composition is another form of code reuse in PMCs. Unlike inheritance, composed roles aren't complete stand-alone PMCs, they are just bundles of behavior and state that can be used within the composing PMC. As such, roles are never instantiated directly, and are never translated to C directly. They have no core structs, though they define attributes to be added to the PMC they are composed into.

When a PMC that uses a role is translated to C, the role provides vtable functions, methods, and attributes that will be added to the generated C code for that PMC. Composed vtable functions, methods, and attributes are not permitted to have the same name as corresponding features defined in the composing PMC. This is called a conflict, and must be explicitly resolved in the composing PMC. When composed features have the same name as inherited vtable functions, methods, or attributes, the composed feature overrides the inherited feature, just as it would if defined in the composing PMC.

Roles are defined using the prole keyword.

  prole <name> <modifiers> {
  }

Roles can compose other roles, but they can't inherit.

Role attributes are defined using the same format as PMC attributes.

Core roles live in src/role and have a file extension of .pr.

Roles are composed into a PMC with the does modifier.

PMCs and high-level objects

High-level objects, as specified in PDD15, need to be able to inherit from PMCs. Subclassing a low-level PMC from a high-level class makes an entry in the high-level class's list of parents.

For PDD15 objects, there is a corresponding instance of the Class PMC. For a low-level PMC, however, the class definition is written in C and compiled away. There needs to be something placed in the parents list for a PDD15 class, that can provide access to the low-level PMC's vtable and methods, and define the storage that the low-level PMC will need within the high-level object. That something is the PMCProxy PMC. Like a PDD15 class, it is stored as the class element in the namespace associated with a PMC, provides introspection facilities and can sit in an inheritance hierarchy.

The PMCProxy PMCs are only created when needed for subclassing a low-level PMC, to avoid a large load of unused PMCProxy objects. When created, they are cached in the class slot of the namespace corresponding to the low-level PMC, so they are only created once.

Therefore, subclassing a PMC looks, at a PIR level, like subclassing a high level class.

  $P0 = get_class 'Hash'
  $P1 = newclass 'MyClass'
  addparent $P1, $P0     # The new class inherits from the Hash PMC

Or, more briefly:

  $P1 = subclass 'Hash', 'MyClass'

PMCs store state in a very different way to PDD15 objects. When a method inherited from a PMC is called on a PDD15 object, that method needs to access the attributes of the inherited low-level PMC. Further, if multiple PMCs are inherited from, they may each have attributes with the same name, that need to be correctly "visible" to the PDD 15 object according to the laws of inheritance. Users of Parrot at a PIR level should not have to care about such issues.

To enable attributes from the low-level PMC to act as full inherited attributes in the child class, the PMCProxy class will create a set of PDD 15 attributes that correspond in type and name to the attributes declared with ATTR in the declaration body of the low-level PMC, as if each had been added with add_attribute. It will also override the GET_ATTR_attrname and SET_ATTR_attrname functions to point to the PDD 15 attributes (with automatic boxing and unboxing for the PMC values) rather than to members of a C struct.

The PMCProxy will also scan the low-level PMC for methods declared with METHOD and insert them in the proxy class as if each had been declared with add_method (possibly with a shim to standardize calling conventions, but hopefully the calling conventions are similar enough between C-defined and PIR-defined methods not to need a shim). The PMCProxy will maintain a link to the low-level PMC's vtable, and use it for any vtable calls that aren't overridden by the proxy class itself.

As a result, a low-level PMC used as a parent of a PDD 15 class will never be instantiated directly. It will only be used as a source for attribute names and types, methods, and a vtable.

When a method is called on an object whose class has low-level PMC parents, the call is made exactly as it would be for PDD 15 parents. The invocant is always the PDD 15 object. Any method or vtable calls made within the low-level PMC are dispatched on the PDD 15 object invocant. This allows the PDD 15 object to intelligently handle method and vtable overrides within multiple parents and itself.

If a low-level PMC expects to be overridden by high-level classes (which means all the core low-level PMC types), it must respect the standard interface.

Definitions

Vtable Functions

Vtables decouple the interface and implementation of various object functions. The actual vtable structure contains pointers to functions that implement the methods for that particular PMC. All pointers must point to valid functions with appropriate prototypes.

In C code, the first parameter to any vtable routine is the current interpreter. The second parameter is the PMC itself.

The following list details each of the vtable functions, their prototypes, and their behavior.

Core Vtable Functions

init
  void init(INTERP, PMC *self)
Called when a PMC is first instantiated. It takes an unused PMC parameter and turns it into a PMC of the appropriate class.
init_pmc
  void init_pmc(INTERP, PMC *self, PMC *initializer)
Alternative entry point called when a PMC is first instantiated. Accepts a PMC parameter used to initialize the given object. Interpretation of the PMC initializer is left open, each PMC is free to choose its own implementation. A null value passed as the initializer parameter is allowed.NOTE: It is strongly suggested that init_pmc(PMCNULL) be equivalent to init(), though there will of necessity be exceptions.
instantiate
  PMC* instantiate(INTERP, PMC *self, PMC *init)
Creates a new PMC object of the type of the class and calls init_pmc(), passing in the initialization argument, init, which is usually a hash. This opcode is most often used with high-level classes, but low-level PMCs may instantiate an object of their own type.
inspect
  PMC* inspect(INTERP, PMC *self)
Return a hash of all characteristics of the self PMC available for introspection.
  PMC* inspect_str(INTERP, PMC *self, STRING *what)
Return a PMC value for one characteristic of the self PMC, selected by string name. Returns PMCNULL if the characteristic doesn't exist.
morph
  void morph(INTERP, PMC *self, INTVAL type)
Turn the PMC into a PMC of type type. If the morphing can't be done in any reasonable way -- for instance if an integer is asked to turn into an Array -- then the PMC is first destroyed, then recreated as an empty PMC of the new type.This method is primarily used when the interpreter has need of coercing a PMC to a particular type, and isn't meant as a general purpose casting tool. Compilers should only emit valid morphing operations.
mark
  void mark(INTERP, PMC *self)
Called when the GC is tracing live PMCs. If this method is called then the code must mark all strings and PMCs that it contains as live, otherwise they may be collected.This method is only called if the GC has detected that this PMC is both alive and has a custom mark routine as indicated by the custom mark PMC flag. (Most normal PMCs don't need a custom mark routine.)If a PMC has this flag set, then it is responsible for marking all buffers and PMCs under its control as alive. If it does not, those PMCs or buffers may be collected later. This method does not have to call the mark method on any PMCs it marks--the GC system takes care of that. (So no need to recurse into aggregate PMCs or anything of the sort).This method may allocate no memory from Parrot, nor may it alter Parrot's internal structures. It should have no side-effects from the C level either. This routine may not throw an exception.
destroy
  void destroy(INTERP, PMC *self)
Called when the PMC is destroyed. This method is called by the GC when it determines that a PMC is dead and that the PMC has marked itself as having a destroy method (an active finalizer).When this method finishes, the PMC will be marked as dead. As such you should make sure that you don't leave any references to it in any Parrot structure by the end of the method.This method may not throw an exception. It will be ignored if it does.
clone
  PMC* clone(INTERP, PMC *self)
Return a clone of a PMC.
defined
  INTVAL defined(INTERP, PMC *self)
Return a true value if the PMC is defined, false otherwise.
get_class
  PMC* get_class(INTERP, PMC *self)
Return the class object for this PMC. For high-level objects, this is a Class object (or other high-level class object). For low-level PMCs, this returns a PMCProxy object.
get_namespace
  PMC* get_namespace(INTERP, PMC *self)
Return the namespace object for this PMC.
freeze
  void freeze(INTERP, PMC *self, visit_info* info)
Freeze the PMC to an archived string format (a bytecode string constant that can be saved in a packfile).
thaw
  void thaw  (INTERP, PMC *self, visit_info* info)
Thaw a PMC from an archived string format (a bytecode string constant that can be saved in a packfile).
thawfinish
  void thawfinish (INTERP, PMC *self, visit_info* info)
Called after the PMC has been thawed to perform any finalization steps.
visit
  void visit (INTERP, PMC *self, visit_info* info)
Used by freeze and thaw to visit the contents of the PMC.
share
  void share(INTERP, PMC *self)

  PMC* share_ro(INTERP, PMC *self)
Mark a PMC as shared and read-only.[NOTE: these seem to be used interchangeably, should be distinguished or merged.]

Accessors

getprop
  PMC* getprop(INTERP, PMC *self, STRING *key)
Return the value from the property hash of self keyed by key. The key should not be null.
setprop
  void setprop(INTERP, PMC *self, STRING *key, PMC *value)
Set the value in the property hash of self that is keyed by key to the value of value. The key should not be null.
delprop
  void delprop(INTERP, PMC *self, STRING *key)
Delete the value from the property hash of self keyed by key. The key should not be null.
getprops
  PMC* getprops(INTERP, PMC *self)
Return the entire property hash for self.
type
  INTVAL type(INTERP, PMC *self)
Return the type of the PMC. Type is a unique number associated with the PMC when the PMC's class is loaded. Negative numbers are considered interpreter-specific, non-public types.
name
  STRING* name(INTERP, PMC *self)
Return the name of the class for the PMC.
get_integer
  INTVAL get_integer(INTERP, PMC *self)
Return the native integer value of the PMC.
get_number
  FLOATVAL get_number(INTERP, PMC *self)
Return the native floating-point value of the PMC.
get_string
  STRING* get_string(INTERP, PMC *self)
Return the native string value of the PMC. This may be in any encoding, chosen by the PMC.
get_repr
  STRING* get_repr(INTERP, PMC *self)
Return a string representation of the PMC. [NOTE: redundant with get_string, candidate for deprecation.]
get_bool
  INTVAL get_bool(INTERP, PMC *self)
Return the true/false value of the PMC (the constant TRUE or the constant FALSE). The definition of truth for a given PMC will depend on the type of the PMC. For a scalar, it may be as simple as returning false when the PMC has a value 0 or "", and returning true when the PMC has any other value.
get_pmc
  PMC* get_pmc(INTERP, PMC *self)
Return the PMC value for this PMC. This is useful in circumstances where the thing being accessed may return something other than its own value. For example, an array might return a reference to itself. Any PMC may return a value different from the PMC that get_pmc is being called on.
set_integer_native
  void set_integer_native(INTERP, PMC *self, INTVAL value)
Set the integer value of this PMC from a native integer value (integer register/constant).
set_integer_same
  void set_integer_same(INTERP, PMC *self, PMC *value)
Set the value of this PMC from the integer value of another PMC. The value PMC is guaranteed to be of the same type as the self PMC, so optimizations may be made.
set_number_native
  void set_number_native(INTERP, PMC *self, FLOATVAL value)
Set the value of this PMC from a native floating-point value (float register/constant).
set_number_same
  void set_number_same(INTERP, PMC *self, PMC *value)
Set the value of this PMC from the floating-point value another PMC. The value PMC is guaranteed to be of the same type as the self PMC, so optimizations may be made.
get_pointer
  void* get_pointer(INTERP, PMC *self)
Returns a pointer value for the PMC. Useful for PMCs that hold pointers to arbitrary data. The details of the data (type, location etc.) depend on the PMC.
set_bignum_int
  void set_bignum_int(INTERP, PMC *self, INTVAL value)
Morph the PMC to a BIGNUM PMC, and set the extended-precision value from a native integer.
set_string_native
  void set_string_native(INTERP, PMC *self, STRING *value)
Set the value of this PMC from a native string value (string register/constant).
assign_string_native
  void assign_string_native(INTERP, PMC *self, STRING *value)
Set the value of this PMC to a copied native string value (string register/constant).
set_string_same
  void set_string_same(INTERP, PMC *self, PMC *value)
Set the value of this PMC from the string value of another PMC. The value PMC is guaranteed to be of the same type as the self PMC, so optimizations may be made.
set_bool
  void set_bool(INTERP, PMC *self, INTVAL value)
Set the boolean state of the PMC to TRUE if the native integer value passed in is TRUE, or FALSE if the value is FALSE. The definition of truth is left open to the particular PMC. For a scalar, it may be as simple as setting false when a 0 value is passed in, and seting true when any other value is passed in.
assign_pmc
  void assign_pmc(INTERP, PMC *self, PMC *value)
Set the value of the PMC in self to the value of the PMC in value by copying the value.
set_pmc
  void set_pmc(INTERP, PMC *self, PMC *value)
Make the PMC in self refer to the PMC passed as value.
set_pointer
  void set_pointer(INTERP, PMC *self, void* value)
Set the pointer value of the PMC Useful for PMCs that hold pointers to arbitrary data. The details of the data (type, location etc.) depend on the PMC.

Aggregate Vtable Functions

Many of the following functions have a *_keyed form, a *_keyed_int form, and a *_keyed_str form. The keyed forms take a PMC *, INTVAL, or STRING * key as a parameter. The PMC * parameter is null (PMCNULL) if there is no key for that PMC; this means that that argument is unkeyed.

In some cases, the caller must provide a non-null key. Those cases are explicitly stated below. In the other cases, you may have to implement the keyed vtable functions and check for a null self key even if you are implementing a non-aggregate type. If the self key is non-null and the PMC class is a non-aggregate type, the _keyed_* methods should throw an exception.

If you do not implement the *_keyed_int and *_keyed_str functions, the default will convert the INTVAL or STRING * into a key PMC * and call the corresponding *_keyed functions.

elements
  INTVAL elements(INTERP, PMC *self)
Return the number of elements in the PMC.
get_integer_keyed
  INTVAL get_integer_keyed(INTERP, PMC *self, PMC *key)
  INTVAL get_integer_keyed_int(INTERP, PMC *self, INTVAL key)
  INTVAL get_integer_keyed_str(INTERP, PMC *self, STRING *key)
Return the integer value for the element indexed by a PMC, integer, or string key. The key is guaranteed not to be null for this function.
get_number_keyed
  FLOATVAL get_number_keyed(INTERP, PMC *self, PMC *key)
  FLOATVAL get_number_keyed_int(INTERP, PMC *self, INTVAL key)
  FLOATVAL get_number_keyed_str(INTERP, PMC *self, STRING *key)
Return the native floating-point value for the element indexed by a PMC, integer, or string key. The key is guaranteed not to be null for this function.
get_string_keyed
  STRING* get_string_keyed(INTERP, PMC *self, PMC *key)
  STRING* get_string_keyed_int(INTERP, PMC *self, INTVAL key)
  STRING* get_string_keyed_str(INTERP, PMC *self, STRING *key)
Return the string value for the element indexed by a PMC, integer, or string key. The key is guaranteed not to be null for this function.
get_pmc_keyed
  PMC* get_pmc_keyed(INTERP, PMC *self, PMC *key)
  PMC* get_pmc_keyed_int(INTERP, PMC *self, INTVAL key)
  PMC* get_pmc_keyed_str(INTERP, PMC *self, STRING *key)
Return the PMC value for the element indexed by a PMC, integer, or string key. The key is guaranteed not to be null for this function.
get_pointer_keyed
  void* get_pointer_keyed(INTERP, PMC *self, PMC *key)
  void* get_pointer_keyed_int(INTERP, PMC *self, INTVAL key)
  void* get_pointer_keyed_str(INTERP, PMC *self, STRING *key)
Return the pointer value for the element indexed by a PMC, integer, or string key. The details of the data (type, location etc.) depend on the PMC.
set_integer_keyed
  void set_integer_keyed(INTERP, PMC *self, PMC *key, INTVAL value)
  void set_integer_keyed_int(INTERP, PMC *self, INTVAL key, INTVAL value)
  void set_integer_keyed_str(INTERP, PMC *self, STRING *key, INTVAL value)
Set the integer value of the element indexed by a PMC, integer, or string key. The key is guaranteed not to be null for this function.
set_number_keyed
  void set_number_keyed(INTERP, PMC *self, PMC *key, FLOATVAL value)
  void set_number_keyed_int(INTERP, PMC *self, INTVAL key, FLOATVAL value)
  void set_number_keyed_str(INTERP, PMC *self, STRING *key, FLOATVAL value)
Set the floating-point value of the element indexed by a PMC, integer, or string key. The key is guaranteed not to be null for this function.
set_string_keyed
  void set_string_keyed(INTERP, PMC *self, PMC *key, STRING *value)
  void set_string_keyed_int(INTERP, PMC *self, INTVAL key, STRING *value)
  void set_string_keyed_str(INTERP, PMC *self, STRING *key, STRING *value)
Set the string value of the element indexed by a PMC, integer, or string key. The key is guaranteed not to be null for this function.
set_pmc_keyed
  void set_pmc_keyed(INTERP, PMC *self, PMC *key, PMC *value)
  void set_pmc_keyed_int(INTERP, PMC *self, INTVAL key, PMC *value)
  void set_pmc_keyed_str(INTERP, PMC *self, STRING *key, PMC *value)
Set the PMC value of the element indexed by a PMC, integer, or string key by copying the value of another PMC.
set_pointer_keyed
  void set_pointer_keyed(INTERP, PMC *self, PMC *key, void* value)
  void set_pointer_keyed_int(INTERP, PMC *self, INTVAL key, void* value)
  void set_pointer_keyed_str(INTERP, PMC *self, STRING *key, void* value)
Set the pointer value of the element indexed by a PMC, integer, or string key.
pop_integer
  INTVAL pop_integer(INTERP, PMC *self)
Return the integer value of the last item on the list, removing that item.
pop_float
  FLOATVAL pop_float(INTERP, PMC *self)
Return the floating-point value of the last item on the list, removing that item.
pop_string
  STRING* pop_string(INTERP, PMC *self)
Return the string value of the last item on the list, removing that item.
pop_pmc
  PMC* pop_pmc(INTERP, PMC *self)
Return the PMC value of the last item on the list, removing that item.
push_integer
  void push_integer(INTERP, PMC *self, INTVAL value)
Add the passed in integer value to the end of the list.
push_float
  void push_float(INTERP, PMC *self, FLOATVAL value)
Add the passed in floating-point number to the end of the list.
push_string
  void push_string(INTERP, PMC *self, STRING *value)
Add the passed in string to the end of the list.
push_pmc
  void push_pmc(INTERP, PMC *self, PMC *value)
Add the passed in PMC to the end of the list.
shift_integer
  INTVAL shift_integer(INTERP, PMC *self)
Return the integer value of the first item on the list, removing that item.
shift_float
  FLOATVAL shift_float(INTERP, PMC *self)
Return the floating-point value of the first item on the list, removing that item.
shift_string
  STRING* shift_string(INTERP, PMC *self)
Return the string value of the first item on the list, removing that item.
shift_pmc
  PMC* shift_pmc(INTERP, PMC *self)
Return the PMC value of the first item on the list, removing that item.
unshift_integer
  void unshift_integer(INTERP, PMC *self, INTVAL value)
Add the passed in integer value to the beginning of the list.
unshift_float
  void unshift_float(INTERP, PMC *self, FLOATVAL value)
Add the passed in floating-point number to the beginning of the list.
unshift_string
  void unshift_string(INTERP, PMC *self, STRING *value)
Add the passed in string to the beginning of the list.
unshift_pmc
  void unshift_pmc(INTERP, PMC *self, PMC *value)
Add the passed in PMC to the beginning of the list.
splice
  void splice(INTERP, PMC *self, PMC *value, INTVAL offset, INTVAL count)
Replace some number of PMCs (specified by the integer count) at offset offset from the beginning of self with the PMCs in the aggregate value.
exists_keyed
  INTVAL exists_keyed(INTERP, PMC *self, PMC *key)
  INTVAL exists_keyed_int(INTERP, PMC *self, INTVAL key)
  INTVAL exists_keyed_str(INTERP, PMC *self, STRING *key)
Check if the element indexed by a PMC, integer, or string key exists.
defined_keyed
  INTVAL defined_keyed(INTERP, PMC *self, PMC *key)
  INTVAL defined_keyed_int(INTERP, PMC *self, INTVAL key)
  INTVAL defined_keyed_str(INTERP, PMC *self, STRING *key)
Check if the element indexed by a PMC, integer, or string key is defined.
delete_keyed
  void delete_keyed(INTERP, PMC *self, PMC *key)
  void delete_keyed_int(INTERP, PMC *self, INTVAL key)
  void delete_keyed_str(INTERP, PMC *self, STRING *key)
Delete the element indexed by a PMC, integer, or string key.

Math Vtable Functions

add
  void add(INTERP, PMC *self, PMC *value, PMC *dest)
  void add_int(INTERP, PMC *self, INTVAL value, PMC *dest)
  void add_float(INTERP, PMC *self, FLOATVAL value, PMC *dest)

  void i_add(INTERP, PMC *self, PMC *value)
  void i_add_int(INTERP, PMC *self, INTVAL value)
  void i_add_float(INTERP, PMC *self, FLOATVAL value)
Add the value of self to the value of a PMC, native integer, or native floating-point number and store the result in a PMC dest. Note that dest may be the same PMC as self; in that case optimizations may be made. The i_ variants perform an inplace operation, modifying the value of self.
subtract
  PMC* subtract(INTERP, PMC *self, PMC *value, PMC *dest)
  PMC* subtract_int(INTERP, PMC *self, INTVAL value, PMC *dest)
  PMC* subtract_float(INTERP, PMC *self, FLOATVAL value, PMC *dest)

  void i_subtract(INTERP, PMC *self, PMC *value)
  void i_subtract_int(INTERP, PMC *self, INTVAL value)
  void i_subtract_float(INTERP, PMC *self, FLOATVAL value)
Subtract the value of a PMC, native integer, or native floating-point number from a PMC and store the result in dest. If dest is null create a result PMC of an appropriate type. Note that dest may be the same PMC as self; in that case optimizations may be made. The i_ variants perform an inplace operation, modifying the value of self.
increment
  void increment(INTERP, PMC *self)
Increment the value of a PMC by 1.
decrement
  void decrement(INTERP, PMC *self)
Decrement the value of a PMC by 1.
multiply
  void multiply(INTERP, PMC *self, PMC *value, PMC *dest)
  void multiply_int(INTERP, PMC *self, INTVAL value, PMC *dest)
  void multiply_float(INTERP, PMC *self, FLOATVAL value, PMC *dest)

  void i_multiply(INTERP, PMC *self, PMC *value)
  void i_multiply_int(INTERP, PMC *self, INTVAL value)
  void i_multiply_float(INTERP, PMC *self, FLOATVAL value)
Multiply a PMC, native integer, or floating-point value by the value of the PMC self and store the result in the dest PMC. Note that dest may be the same PMC as self; in that case optimizations may be made. The i_ variants perform an inplace operation, modifying the value of self.
divide
  void divide(INTERP, PMC *self, PMC *value, PMC *dest)
  void divide_int(INTERP, PMC *self, INTVAL value, PMC *dest)
  void divide_float(INTERP, PMC *self, FLOATVAL value, PMC *dest)

  void i_divide(INTERP, PMC *self, PMC *value)
  void i_divide_int(INTERP, PMC *self, INTVAL value)
  void i_divide_float(INTERP, PMC *self, FLOATVAL value)
Divide the value of the self PMC by a PMC, native integer, or native floating-point number and store the result in dest. Note that dest may be the same PMC as self; in that case optimizations may be made. The i_ variants perform an inplace operation, modifying the value of self.
floor_divide
  PMC* floor_divide(INTERP, PMC *self, PMC *value, PMC *dest)
  PMC* floor_divide_int(INTERP, PMC *self, INTVAL value, PMC *dest)
  PMC* floor_divide_float(INTERP, PMC *self, FLOATVAL value, PMC *dest)

  void i_floor_divide(INTERP, PMC *self, PMC *value)
  void i_floor_divide_int(INTERP, PMC *self, INTVAL value)
  void i_floor_divide_float(INTERP, PMC *self, FLOATVAL value)
Divide the PMC's value number by value and return the result in dest. The result is the floor() of the division i.e. the next whole integer towards -inf. If the denominator is zero, a 'Divide by zero' exception is thrown. The i_ variants perform an inplace operation, modifying the value of self.
modulus
  void modulus(INTERP, PMC *self, PMC *value, PMC *dest)
  void modulus_int(INTERP, PMC *self, INTVAL value, PMC *dest)
  void modulus_float(INTERP, PMC *self, FLOATVAL value, PMC *dest)

  void i_modulus(INTERP, PMC *self, PMC *value)
  void i_modulus_int(INTERP, PMC *self, INTVAL value)
  void i_modulus_float(INTERP, PMC *self, FLOATVAL value)
Divide the value of the self PMC by the value of a PMC, native integer, or native floating-point number and store the remainder in dest. Note that dest may be the same PMC as self; in that case optimizations may be made. The i_ variants perform an inplace operation, modifying the value of self.
cmodulus
  void cmodulus(INTERP, PMC *self, PMC *value, PMC *dest)
  void cmodulus_int(INTERP, PMC *self, INTVAL value, PMC *dest)
  void cmodulus_float(INTERP, PMC *self, FLOATVAL value, PMC *dest)

  void i_cmodulus(INTERP, PMC *self, PMC *value)
  void i_cmodulus_int(INTERP, PMC *self, INTVAL value)
  void i_cmodulus_float(INTERP, PMC *self, FLOATVAL value)
Divide the value of the self PMC by the value of a PMC, native integer, or native floating-point number and store the remainder in dest. Note that dest may be the same PMC as self; in that case optimizations may be made. The i_ variants perform an inplace operation, modifying the value of self.Note that modulus uses Knuth's "corrected mod" algorithm, as implemented in src/utils.c, while cmodulus uses the C-style fmod function.
pow
  PMC* pow(INTERP, PMC *self, PMC *value, PMC *dest)
  PMC* pow_int(INTERP, PMC *self, INTVAL value, PMC *dest)
  PMC* pow_float(INTERP, PMC *self, FLOATVAL value, PMC *dest)

  void i_pow(INTERP, PMC *self, PMC *value)
  void i_pow_int(INTERP, PMC *self, INTVAL value)
  void i_pow_float(INTERP, PMC *self, FLOATVAL value)
Return the value of self raised to the power of value. The i_ variants perform an inplace operation, modifying the value of self.
absolute
  PMC* absolute(INTERP, PMC *self, PMC *dest)
  void i_absolute(INTERP, PMC *self)
Return the absolute value of self. The i_ variant performs an inplace operation, modifying the value of self.
neg
  void neg(INTERP, PMC *self, PMC *dest)
  void i_neg(INTERP, PMC *self)
Negate the sign of self and store the result in dest. Note that self and dest may refer to the same PMC, in which case optimizations may be made. The i_ variant performs an inplace operation, modifying the value of self.

Logical Vtable Functions

bitwise_or
  void bitwise_or(INTERP, PMC *self, PMC *value, PMC *dest)
  void bitwise_or_int(INTERP, PMC *self, INTVAL value, PMC *dest)
  void i_bitwise_or(INTERP, PMC *self, PMC *value)
  void i_bitwise_or_int(INTERP, PMC *self, INTVAL value)
Calculate the bitwise-OR of the value of the self PMC and the value of a PMC or native integer and store the result in dest. Note that dest may be the same PMC as self; in that case optimizations may be made. [Question: what happens when the self and value PMCs aren't integers?]The i_ variants perform an inplace operation and store the result in self.
bitwise_and
  PMC* bitwise_and(INTERP, PMC *self, PMC *value, PMC *dest)
  PMC* bitwise_and_int(INTERP, PMC *self, INTVAL value, PMC *dest)
  void i_bitwise_and(INTERP, PMC *self, PMC *value)
  void i_bitwise_and_int(INTERP, PMC *self, INTVAL value)
Return the result of a bitwise AND on the passed in value and the self PMC. The i_ variants perform an inplace operation and store the result in self.
bitwise_xor
  PMC* bitwise_xor(INTERP, PMC *self, PMC *value, PMC *dest)
  PMC* bitwise_xor_int(INTERP, PMC *self, INTVAL value, PMC *dest)
  void i_bitwise_xor(INTERP, PMC *self, PMC *value)
  void i_bitwise_xor_int(INTERP, PMC *self, INTVAL value)
Return the result of a bitwise XOR on the passed in value and the self PMC. The i_ variants perform an inplace operation and store the result in self.
bitwise_ors
  PMC* bitwise_ors(INTERP, PMC *self, PMC *value, PMC *dest)
  PMC* bitwise_ors_str(INTERP, PMC *self, STRING *value, PMC *dest)
  void i_bitwise_ors(INTERP, PMC *self, PMC *value)
  void i_bitwise_ors_str(INTERP, PMC *self, STRING *value)
Return the result of a bitwise OR over an entire string on the passed in value and the self PMC. The i_ variants perform an inplace operation and store the result in self.
bitwise_ands
  PMC* bitwise_ands(INTERP, PMC *self, PMC *value, PMC *dest)
  PMC* bitwise_ands_str(INTERP, PMC *self, STRING *value, PMC *dest)
  void i_bitwise_ands(INTERP, PMC *self, PMC *value)
  void i_bitwise_ands_str(INTERP, PMC *self, STRING *value)
Return the result of a bitwise AND over an entire string on the passed in value and the self PMC. The i_ variants perform an inplace operation and store the result in self.
bitwise_xors
  PMC* bitwise_xors(INTERP, PMC *self, PMC *value, PMC *dest)
  PMC* bitwise_xors_str(INTERP, PMC *self, STRING *value, PMC *dest)
  void i_bitwise_xors(INTERP, PMC *self, PMC *value)
  void i_bitwise_xors_str(INTERP, PMC *self, STRING *value)
Return the result of a bitwise XOR over an entire string on the passed in value and the self PMC. The i_ variants perform an inplace operation and store the result in self.
bitwise_not
  PMC* bitwise_not(INTERP, PMC *self, PMC *dest)
  void i_bitwise_not(INTERP, PMC *self)
Returns the bitwise negation of the self PMC. The i_ variant performs an inplace operation, storing the result in self.
bitwise_nots
  PMC* bitwise_nots(INTERP, PMC *self, PMC *dest)
  void i_bitwise_nots(INTERP, PMC *self)
Returns the bitwise negation of the string self PMC. The i_ variant performs an inplace operation, storing the result in self.
bitwise_shl
  PMC* bitwise_shl(INTERP, PMC *self, PMC *value, PMC *dest)
  PMC* bitwise_shl_int(INTERP, PMC *self, INTVAL value, PMC *dest)
  void i_bitwise_shl(INTERP, PMC *self, PMC *value)
  void i_bitwise_shl_int(INTERP, PMC *self, INTVAL value)
Return the value of the self PMC bitwise shifted left by the amount specified in value, shifting in zeroes on the right (arithmetic/logical bitwise shift). A negative value shifts right. The i_ variants perform an inplace operation, storing the result in self.The result may be promoted to a BigInt.
bitwise_shr
  PMC* bitwise_shr(INTERP, PMC *self, PMC *value, PMC *dest)
  PMC* bitwise_shr_int(INTERP, PMC *self, INTVAL value, PMC *dest)
  void i_bitwise_shr(INTERP, PMC *self, PMC *value)
  void i_bitwise_shr_int(INTERP, PMC *self, INTVAL value)
Return the value of the self PMC bitwise shifted right by the amount specified in value, shifting in copies of the sign bit on the left (arithmetic bitwise shift). A negative value shifts left. The i_ variants perform an inplace operation, storing the result in self.The result may be promoted to a BigInt (when value is negative).
bitwise_lsr
  PMC* bitwise_lsr(INTERP, PMC *self, PMC *value, PMC *dest)
  PMC* bitwise_lsr_int(INTERP, PMC *self, INTVAL value, PMC *dest)
  void i_bitwise_lsr(INTERP, PMC *self, PMC *value)
  void i_bitwise_lsr_int(INTERP, PMC *self, INTVAL value)
Return the value of the self PMC bitwise shifted right by the amount specified in value, shifting in zeroes on the left (logical bitwise shift). A negative value shifts left. The i_ variants perform an inplace operation, storing the result in self.
is_equal
  INTVAL is_equal(INTERP, PMC *self, PMC *value)
  INTVAL is_equal_num(INTERP, PMC *self, PMC *value)
  INTVAL is_equal_string(INTERP, PMC *self, PMC *value)
Return an integer value (1/0) indicating if the self PMC is equal to the value PMC. The _num version tests for numeric equality, while the _string version tests for string equality.
is_same
  INTVAL is_same(INTERP, PMC *self, PMC *value)
Return an integer value (1/0) indicating if self is the same as value (with "sameness" determined by each PMC).
cmp
  INTVAL cmp(INTERP, PMC *self, PMC *value)
  INTVAL cmp_num(INTERP, PMC *self, PMC *value)
  INTVAL cmp_string(INTERP, PMC *self, PMC *value)
Returns the integer result of comparing the values of self and value (0 for equal, 1 if self is greater, -1 if value is greater). The _num version performs a numeric comparison, while the _string version performs a string comparison.

String Vtable Functions

concatenate
  PMC* concatenate(INTERP, PMC *self, PMC *value, PMC *dest)
  PMC* concatenate_str(INTERP, PMC *self, STRING *value, PMC *dest)
  void i_concatenate(INTERP, PMC *self, PMC *value)
  void i_concatenate_str(INTERP, PMC *self, STRING *value)
Concatenate self with a PMC or string value and return the result. The i_ variant performs an inplace concatenation, modifying the value of self.
repeat
  PMC* repeat(INTERP, PMC *self, PMC *value, PMC *dest)
  PMC* repeat_int(INTERP, PMC *self, INTVAL value, PMC *dest)
  void i_repeat(INTERP, PMC *self, PMC *value)
  void i_repeat_int(INTERP, PMC *self, INTVAL value)
Return the result of repeating the value in self the number of times indicated in value. The i_ variants perform an inplace operation, modifying the value of self.
substr
  STRING* substr(INTERP, PMC *self, INTVAL offset, INTVAL length)
Extracts the string starting at offset with size length and return it as a PMC in dest or as a string return value.

Code Vtable Functions

invoke
  opcode_t* invoke(INTERP, PMC *self, void* next)
Invoke the code object self.

Class/Object Vtable Functions

can
  INTVAL can(INTERP, PMC *self, STRING *method)
Return a true value if the PMC has a method named method, return 0 otherwise.
isa
  INTVAL isa(INTERP, PMC *self, STRING *classname)
Return a true value if the PMC inherits from the class named classname, return 0 otherwise.
does
  INTVAL does(INTERP, PMC *self, STRING *role)
Return a true value if the PMC does (composes) or performs (satisfies the interface of) the role named role, return 0 otherwise.
get_attr
  PMC* get_attr_str(INTERP, PMC *self, STRING *idx)
Retrieve an attribute value from the PMC (instance object).
set_attr
  void set_attr_str(INTERP, PMC *self, STRING *idx, PMC *value)
Store an attribute value in the PMC (instance object).
add_parent
  void add_parent(INTERP, PMC *self, PMC *parent)
Add a parent to the PMC (class object), establishing an inheritance relation.
remove_parent
  void remove_parent(INTERP, PMC *self, PMC *parent)
Remove a parent from a PMC (class object).Not all object metamodels will support removing parents.
add_role
  void add_role(INTERP, PMC *self, PMC *role)
Add a role to the PMC (class object), establishing a composition relation.
remove_role
  void remove_role(INTERP, PMC *self, PMC *role)
Remove a role from the PMC (class object).Not all object metamodels will support removing roles.
add_attribute
  void add_attribute(INTERP, PMC *self, STRING *name, PMC *type)
Add an attribute to the PMC (class object).
remove_attribute
  void remove_attribute(INTERP, PMC *self, STRING *name)
Remove an attribute from the PMC (class object).Not all object metamodels will support removing attributes.
add_method
  void add_method(INTERP, PMC *self, STRING *method_name, PMC *sub_pmc)
Add a method to the PMC (class object).
remove_method
  void remove_method(INTERP, PMC *self, STRING *method_name)
Remove a method from the PMC (class object).Not all object metamodels will support removing methods.
add_vtable_override
  void add_vtable_override(INTERP, PMC *self, STRING *vtable_name,
                           PMC *sub_pmc)
Add a vtable override to the PMC (class object).
  void remove_vtable_override(INTERP, PMC *self, STRING *vtable_name)
Remove a vtable override from the PMC (class object).
find_method
  PMC* find_method(INTERP, PMC *self, STRING *method_name)
Return a subroutine PMC for the passed method name. This subroutine PMC may be cached, so the method must return an equivalent sub PMC each time, or be capable of dealing with the returned sub PMCs being reused. [Why should it be cached? Can you turn off caching? What if you want to override find_method to generate methods on the fly?]

Core PMCs

Parrot has a number of core PMC types that all programs can guarantee will be available to them. (With the possible exception of Parrot programs executing on an embedded device or other restricted environment)

Scalar types

Undef
This is the generic no-value type. It has a numeric value of zero, a string value of empty string, and a boolean value of false. It will, on assignment, turn itself into a PMC of the source type, or if assigned a basic type will turn itself into one of the wrapper PMC types (detailed below) for the basic types.
Integer
The PMC wrapper for Parrot's low-level integer type. Always an integer, with other types auto-converted to an integer when stored into this PMC. The range and behaviour of the Integer PMC is identical to the platform low-level integer.The boolean value for an Integer is false if zero, otherwise true.Floating point, string, and bignum values assigned to an Integer PMC round to the nearest integer. Floats, or strings which resolve to numbers, cap at the platform maximum or minimum integer value.Integer PMCs take on a value of 1 if a boolean true is assigned, and a value of 0 if a boolean false is assigned.If an out-of-range value is assigned to an Integer PMC, the PMC will throw an exception if exact math is enabled.
Float
The PMC wrapper for Parrot's low-level floating-point type. Always a float, with other types autoconverted to a float when stored into this PMC.The boolean value for a Float is false if exactly zero, otherwise true.When converted to an integer, floats round to the closest integer, capping at the platform maximum or minimum integer value.When converting to a string, floats use the platform default snprintf format.
String
The PMC wrapper for Parrot's low-level string type. Always a simple string, with other types autoconverted to a string when stored into this PMC.The boolean value for a String is false if empty or the string '0' (a one character string holding a zero) otherwise true. This PMC autoconverts to an integer or float when its integer or float value is fetched.
Boolean
A true/false value. Returns 0 for false, 1 for true when fetched as an integer or float, empty string for false and '1' for true when fetched as a string.
BigInt
An arbitrary precision integer.
BigNum
The PMC wrapper for Parrot's low-level BigNum type. {{ NOTE: this type doesn't seem to exist. }}
Complex
A complex number, consisting of a real part and an imaginary part. {{ NOTE: is this a complete and useful implementation of complex numbers? }}
Class
The PMC for Parrot's class.
Object
The PMC for Parrot's base object type.
Ref
The PMC that represents a reference to another PMC. Delegates all functions to the referred-to PMC.
AggregateElementRef
This PMC represents a reference to an element contained in an aggregate PMC type, such as an array or hash. It is initialized with the key being referenced and the aggregate PMC containing that key.Note that assigning to the reference PMC will be equivalent to a keyed set on the referenced aggregate PMC - that is, it modifies the element rather than doing a v-table call on the element itself. It is important to be aware of this when assigning a PMC through this reference; it is not the same behaviour as the Ref PMC.
WeakRegisterRef
This PMC represents a weak reference to a register. Should the reference live beyond the context containing the register that it references, any attempt to use the reference will throw an exception.A weak register reference can only be created by the register_ref opcode. Any assignment to the register will behave like a set instruction. That is, when assigning a PMC using a WeakRegisterRef PMC, the register will be updated to reference that PMC rather than calling the assign v-table call on the PMC in that register. This is not the same behaviour as the Ref PMC.
Exception
The base class for all exceptions. Currently based on ResizablePMCArray, but that's likely to change.

Array types

Note that for the following types you can set the size of the array by using the VTABLE_set_integer_native() function. Assigning an integer to the array as a whole sets the array to that size.

Size-changing operations (such as push, pop, shift, unshift, and splice) on statically-sized arrays will throw an exception.

ResizablePMCArray returns Undef for unset elements (so does the new object model, because it uses ResizablePMCArray for storage), but Hash returns PMCNULL. Standardize all core aggregate PMC types on the singleton PMCNULL.

Array
The base class for all array types (a statically sized array for any arbitrary type). New array types can be derived from the base Array. In user code it is recommended to use one of the specific array types below, rather than the base type.
FixedBooleanArray
A statically sized array which holds only Boolean values.
ResizableBooleanArray
A dynamically sized array which holds only Boolean values.
FixedIntegerArray
A statically sized array which holds only Integer values.
ResizableIntegerArray
A dynamically sized array which holds only Integer values.
FixedFloatArray
A statically sized array which holds only Float values.
ResizableFloatArray
A dynamically sized array which holds only Float values.
FixedPMCArray
A statically sized array which holds only PMC values.
ResizablePMCArray
A dynamically sized array which holds only PMC values.
FixedStringArray
A statically sized array which holds only String values.
ResizableStringArray
A dynamically sized array which holds only String values.

Hash types

Hash
A container with key-value semantics. The values are PMCs.
Env
Env is a singleton PMC class, that is there is only one Env PMC in any interpreter. This PMC gives access to the process' environment variables--reading from it returns the value of the named process environment variable, while writing to it sets the value of a process environment variable. For example, to retrieve the current value of TERM (the terminal type on most Unix systems):
   new P1, 'Env'
   set S1, P1['TERM']
Note that an embedding system may override this behavior.
NameSpace
Stores one level of a namespace. Every slot in a namespace contains either another namespace (the next level down), or a variable or subroutine/method.
OrderedHash
A hash that also preserves the order of elements, providing the interface of both a hash and an array.
AddrRegistry
Simulates reference counting for dead-object detection and garbage collection.

Subroutine types

Sub
A fundamental subroutine object, and base class for other subroutine PMC types.
Closure
A closure: subroutine object plus captured lexical scope.
Continuation
A continuation: a subroutine object that captures the interpreter's context at the point where the continuation was constructed.
Coroutine
A coroutine: a continuation object that can stop part way through execution and restart at the point where it left off the next time it's called.
Eval
An extension of Sub that provides dynamic code evaluation and execution.
ExceptionHandler
A code object for handling exceptions.
MultiSub
A container for multiply dispatched subroutines.
NCI
A native call interface wrapper around a C function.
Bound_NCI
An internal NCI method call bound to a particular call instance.
Compiler
A subroutine implementing a language compiler. (Derived from NCI.)

References

docs/pmc2c.pod