Classes and Objects
Many of Parrot's core classes -- such as Integer
, String
, or ResizablePMCArray
-- are written in C, but you can also write your own classes in PIR. PIR doesn't have the shiny syntax of high-level object-oriented languages, but it provides the necessary features to construct well-behaved objects every bit as powerful as those of high-level object systems.
Parrot developers often use the word "PMCs" to refer to the objects defined in C classes and "objects" to refer to the objects defined in PIR. In truth, all PMCs are objects and all objects are PMCs, so the distinction is a community tradition with no official meaning.
Class Declaration
The newclass
opcode defines a new class. It takes a single argument, the name of the class to define.
Just as with Parrot's core classes, the new
opcode instantiates a new object of a named class.
In addition to a string name for the class, new
can also instantiate an object from a class object or from a keyed namespace name.
Attributes
The addattribute
opcode defines a named attribute -- or instance variable -- in the class:
The setattribute
opcode sets the value of a declared attribute. You must declare an attribute before you may set it. The value of an attribute is always a PMC, never an integer, number, or string.Though it can be an Integer
, Number
, or String
PMC.
The getattribute
opcode fetches the value of a named attribute. It takes an object and an attribute name as arguments and returns the attribute PMC:
Because PMCs are containers, you may modify an object's attribute by retrieving the attribute PMC and modifying its value. You don't need to call setattribute
for the change to stick:
Instantiation
With a created class, we can use the new
opcode to instantiate an object of that class in the same way we can instantiate a new PMC.
Or, if we don't have the class object handy, we can do it by name too:
PMCs have two VTABLE interface functions for dealing with instantiating a new object: init
and init_pmc
. The former is called when a new PMC is created, the later is called when a new PMC is created with an initialization argument.
Methods
Methods in PIR are subroutines stored in the class object. Define a method with the .sub
directive and the :method
modifier:
This method returns the integer value of the bar
attribute of the object divided by two. Notice that the code never declares the named variable self
. Methods always make the invocant object -- the object on which the method was invoked -- available in a local variable called self
.
The :method
modifier adds the subroutine to the class object associated with the currently selected namespace, so every class definition file must contain a .namespace
declaration. Class files for languages may also contain an .HLL
declaration to associate the namespace with the appropriate high-level language:
Method calls in PIR use a period (.
) to separate the object from the method name. The method name is either a literal string in quotes or a string variable. The method call looks up the method in the invocant object using the string name:
You can also pass a method object to the method call instead of looking it up by string name:
Parrot always treats a PMC used in the method position as a method object, so you can't pass a String
PMC as the method name.
Methods can have multiple arguments and multiple return values just like subroutines:
The can
opcode checks whether an object has a particular method. It returns 0 (false) or 1 (true):
Inheritance
The subclass
opcode creates a new class that inherits methods and attributes from another class. It takes two arguments: the name of the parent class and the name of the new class:
subclass
can also take a class object as the parent class instead of a class name:
The addparent
opcode also adds a parent class to a subclass. This is especially useful for multiple inheritance, as the subclass
opcode only accepts a single parent class:
To override an inherited method in the child class, define a method with the same name in the subclass. This example code overrides Bar
's who_am_i
method to return a more meaningful name:
Object creation for subclasses is the same as for ordinary classes:
Calls to inherited methods are just like calls to methods defined in the class:
The isa
opcode checks whether an object is an instance of or inherits from a particular class. It returns 0 (false) or 1 (true):
Overriding Vtable Functions
The Object
PMC is a core PMC written in C that provides basic object-like behavior. Every object instantiated from a PIR class inherits a default set of vtable functions from Object
, but you can override them with your own PIR subroutines.
The :vtable
modifier marks a subroutine as a vtable override. As it does with methods, Parrot stores vtable overrides in the class associated with the currently selected namespace:
Subroutines acting as vtable overrides must either have the name of an actual vtable function or include the vtable function name in the :vtable
modifier:
You must call methods on objects explicitly, but Parrot calls vtable functions implicitly in multiple contexts. For example, creating a new object with $P3 = new 'Foo'
will call init
with the new Foo
object.
As an example of some of the common vtable overrides, the =
operator (or set
opcode) calls Foo
's vtable function set_integer_native
when its left-hand side is a Foo
object and the argument is an integer literal or integer variable:
The +
operator (or add
opcode) calls Foo
's add
vtable function when it adds two Foo
objects:
The inc
opcode calls Foo
's increment
vtable function when it increments a Foo
object:
Parrot calls Foo
's get_integer
and get_string
vtable functions to retrieve an integer or string value from a Foo
object:
Introspection
Classes defined in PIR using the newclass
opcode are instances of the Class
PMC. This PMC contains all the meta-information for the class, such as attribute definitions, methods, vtable overrides, and its inheritance hierarchy. The opcode inspect
provides a way to peek behind the curtain of encapsulation to see what makes a class tick. When called with no arguments, inspect
returns an associative array containing data on all characteristics of the class that it chooses to reveal:
When called with a string argument, inspect
only returns the data for a specific characteristic of the class:
Table 7-1 shows the introspection characteristics supported by inspect
.
1 POD Error
The following errors were encountered while parsing the POD:
- Around line 64:
Deleting unknown formatting code N<>