This file is part of the Perl 6 Archive

To see what is currently happening visit http://www.perl6.org/

NAME

docs/pdds/pdd15_objects.pod - Object and Class semantics for Parrot

ABSTRACT

This PDD describes the semantics of Parrot's object and class systems. The PDD is divided into two parts, the semantics expressed to user programs through PMCs, and the default back-end class scheme.

Note that the class system is not the single mandated class scheme, merely the one designed to express the semantics needed for perl 6, ruby, and python. Alternate class systems are certainly possible, and direct compatibility with the system as described here isn't strictly necessary.

DESCRIPTION

This is a reasonably straightforward object system. It assumes that objects have:

and that you can:

Additionally we assume that all objects can have properties on them, as all PMCs can have properties. The property get/set method may be overridden on a per-class basis as any other vtable method may be.

For classes, we assume that:

And we further assume that classes can:

This list is likely not definitive, but it's enough to start with. It also doesn't address the semantics of method calls, which need to be dealt with, possibly separately. With that in mind, the object system supports these features with a combination of PMC classes (not to be confused with object classes) and opcodes.

IMPLEMENTATION

There are four pieces to the object implementation. There are the PMCs for the classes and objects, the opcodes the engine uses to do objecty things, the specific vtable methods used to perform those objecty things, and the supporting code provided by the interpreter engine to do the heavy lifting.

Please note that Parrot, in general, does not restrict operations on objects and classes. If a language has restrictions on what can be done with them, the language is responsible for making sure that disallowed things do not happen. For example, Parrot permits multiple inheritance, and will not stop code that adds a new parent to an existing class. If a language doesn't allow for multiple inheritance it must not emit code which would add multiple parents to a class. (Parrot may, at some point, allow imposition of runtime restrictions on a class, but currently it doesn't)

PMCs

There are two PMC classes, ParrotClass and ParrotObject. ParrotObject PMCs are the actual objects, and hold all the per-object instance data. ParrotClass PMCs hold all the class-specific information. Instantiating a new OO class creates a new ParrotClass PMC, and enters the new OO class into Parrot's PMC class table, at which point it is indistinguishable from any other PMC class. (This doesn't mean that non-ParrotClass things can be subclassed or treated as an OO class. Neither is that forbidden. Just unimplemented)

It's important to note that all 'standard' classes are ParrotClass PMC instances, and all 'standard' objects are ParrotObject PMCs. We do not create a brand new PMC class for each OO class, and they all share the ParrotClass or ParrotObject vtable, respectively. This distinction is mostly an artifact of the implementation, and may change in the future.

While the internals of the class and object PMCs should be considered black boxes, here's some documentation as to what they are for implementation purposes.

The ParrotClass PMC holds a 6 element array, which is:

Note that the attribute catalog holds all the attributes for an object. This includes the attributes in the object's class as well as all the attributes defined in all the parent classes. (Multiple inheritance makes this necessary -- the offsets of a class' attributes will change from child class to child class)

ParrotClass PMCs also have the "I am a class" flag set on them.

The ParrotObject PMC is an array of meta-information and attributes. The elements of this array are:

Note that ParrotObject PMCs also have the "I am an object" flag set on them.

Opcodes

The following ops are provided to deal with objects. Please note that method calls are governed by parrot's calling conventions, and as such objects, method PMCs, return continuations, and parameters must be in the right places, though some ops will put parameters where they need to go.

Vtables

To make this work all PMCs must have the following vtable entries. They may, for non-objects, throw an exception.

The catalog metadata for objects is considered to be attributes on the class, so to get the offset for a class for an object, you fetch the object's class then look up the offset attribute from it. (The class attributes are detailed later) This is safe in general, since the only code reasonably querying a class' attribute list is the class code itself, and if a class doesn't know whether it's a ParrotClass-style class or not you've got bigger problems.

Currently Parrot only supports mutating a class' metainformation for ParrotClass classes. This is a restriction which will be lifted at some point soon.

What The Bytecode Sees

The bytecode is isolated from most of the internal details of the implementation. This allows both for flexibility in the implementation and forward compatibility, generally good things. It also allows for multiple concurrent interoperable object systems. The major thrust is for transparent use of objects, though most class activity (including creation of subclasses and modifications of existing classes) should be transparent as well.

EXAMPLES

The following examples all assume we're working with basic ParrotObject objects and ParrotClass classes.

Creating a new class

To create a new class Foo which has no parent classes:

   newclass $P0, "Foo"

Creating a new class with multiple parents

To create a class Foo with the parents A and B, the code would be:

   getclass $P0, "A"
   getclass $P1, "B"
   subclass $P2, $P0, "Foo"
   addparent $P2, $P1

Creating a new class with attributes

Adding the attributes a and b to the new class Foo:

  newclass $P0, "Foo"
  addattribute $P0, "a"   # This is offset 0 + classoffset
  addattribute $P0, "b"   # This is offset 1 + classoffset

Instantiating an object

Assuming we want an object of class Foo:

  .local int FooType
  .local pmc MyObject
  find_type FooType, "Foo"
  new MyObject, FooType

Calling a method on an object

Calling the method Xyzzy on an object, assuming the PDD03 calling conventions are respected:

  callmethod "Xyzzy"

  set S0, "Xyzzy"
  callmethod

Or, if a return continuation needs constructing:

  callmethodcc "Xyzzy"

  set S0, "Xyzzy"
  callmethodcc

Accessing attributes from within a class

Assuming we've an object that has class Foo in it somewhere and want to get the second attribute b out of it:

  .local int BaseOffset
  .local int BOffset
  classoffset BaseOffset, $P0, "Foo"
  BOffset = BaseOffset + 1
  getattribute $P1, $P0, BOffset

Or with named access, if it isn't time critical:

  getattribute $P1, $P0, "Foo\x0b"

Explanations

To get a new class, you can do a newclass, which creates a new class with no parents besides parrot's default super-ish parent class. (Which doesn't appear in the class list anywhere, though arguably it ought to)

To get a new child class, you have two potential options:

Both ways work. It is, however, more efficient to use the first method, and just subclass the immediate parent class of your new class.

When adding in extra parents in a multiple-inheritance scenario, subclass the first class in the immediate parent list then use the addparent op to add in the rest of the immediate parents.

Do be aware that, right now, you should not add attributes or parents to a class that's been subclassed or has had objects instantiated. This will leave the internal structures of the classes and objects in an inconsistent state and things won't work at all the way you want them to. At the moment parrot won't warn if you do this, but it will soon. The restriction on parent list changes and attribute addition will be lifted in future releases, though doing so will be an expensive operation.

VTABLE OVERLOADING

Classes may override the vtable methods, allowing objects of a class to behave like a primitive PMC. Each vtable slot has a corresponding named method that parrot looks for in your class hierarchy when an object is used in a primitive context.

To use these properly at a low-level requires a good working knowledge of the way Parrot works--generally for higher-level languages the language compiler or runtime will provide easier-to-use wrappers. These methods are all prototyped, and take a single fixed argument list, and return at most a single value.

While vtable methods may take a continuation, those continuations may not escape the vtable method's execution. This is due to the way that vtable methods are called by the interpreter--once a vtable method is exited any continuation taken within it is no longer valid and may not be used.

Note that any class method that wishes to use parrot's multi-method dispatch system may do so. This is, in fact, encouraged, though it is not required. In the absence of explicit multimethod dispatch, a left-side wins scheme is used.

The following list details the raw method names:

TRANSLATION AND GLOSSARY

Since every object system on the planet shares a common set of terms but uses them completely differently, this section defines

Glossary

Translation

The following list a set of languages, then within each language what the parrot term translates to.

ATTACHMENTS

None.

FOOTNOTES

None.

REFERENCES

None.

VERSION

CURRENT

    Maintainer: Dan Sugalski
    Class: Internals
    PDD Number: 15
    Version: 1.2
    Status: Developing
    Last Modified: February 09, 2004
    PDD Format: 1
    Language: English

HISTORY

CHANGES