In order to ensure the interoperability among object representations and even between different object systems that uses the same representation. In this context we need to define the HOW and REPR API, this is the SMOP OO API that allows representations to be interchanged, and custom BUILD methods to be written. The interesting aspect is that all this methods must be called in the object itself in SMOP, and that's why they have the "^" and "^!" prefixes, where the first mean a HOW call, and the second means a REPR call.

It is important to stress that the REPR API is SMOP specific, whereas the HOW API is supposed to be transversal to Perl 6 implementations.

Follows an example on how a pure-prototype-oo based invocation would work.

Image a bit inacurrate, but general idea is correct.

Object API

This is what is implemented by Object

method new($prototype: *@protoobjects, *%initialize --> Object) {...}
method bless($prototype: $candidate?, *@protoobjects, *%initialize --> Object) {...}
method clone($object: --> Object ) {...}
method can($object: $name, $capture? --> List of Method) {...}
method does($object: $prototype --> bool) {...}
method isa($object: $prototype --> bool) {...}
method defined($object: --> bool ) {...}
method CREATE($prototype: :$repr --> Object) {...}
method BUILDALL($object: *@protoobjects, *%initialize) {...}
method DESTROYALL($object: ) {...}
submethod BUILD($object: *@protoobjects, *%initialize) {...}
submethod DESTROY($object: ) {...}

Attribute API

method name( --> Str ) {...}
method private_name( --> Str) {...}
method create_container( --> Object) {...}

Method API

method name( --> Str ) {...}
method postcircumfix:<()>($method: $capture --> Object)


This is the instrospection API, that is available as standard Perl 6 and relate to the Object considering all the inheritance and composition. This represent all object capabilities, including the inherited ones, not only the ones implemented by this specific instance (as opposed to the REPR API).

The HOW calls are made using the HOW object as the invocant and the object as a prepended positional argument. The name in that calls won't keep the "^" prefix. This means that HOW is just a class that must follow this API.

method CREATE($how: $prototype, :$repr --> Object ) {...}
method bless($how: $prototype, $candidate?, *@protoobjects, *%initialize --> Object) {...}
method BUILDALL($how: $object, *@protoobjects, *%initialize) {...}
method DESTROYALL($how: $object ) {...}
method clone($how: $object --> Object ) {...}
method defined($how: $object --> bool ) {...}
method methods($how: $object --> List of Method ) {...}
method attributes($how: $object --> List of Attribute ) {...}
method isa($how: $object, $superclass --> bool ) {...}
method does($how: $object, $otherclass --> bool ) {...}
method can($how: $object, $identifier, $capture? --> List of Method) {...}
method dispatch($how: $object, $identifier, $capture --> Any) {...}

Declaration API

method add_method($how: $object, $name, $code) {...}
method add_attribute($how: $object, $name, $attribute) {...}
method compose_role($how: $object, $role) {...}


The representation API defines how the runtime can ask different representations. This API is the real enabler on having different representations, even for the same classes. Unlike the HOW API, this only applies to this specific object. The responder interface is supposed to intercept that calls and never call them using standard MRO. None of the information returned by the methods of the REPR API reflects inherited behaviours, it reflects only the definitions made in that object.

Basic initialization and destruction API.

# .^!CREATE is called to initialize a clean p6opaque (no proto, no instance)
method ^!CREATE($prototype: ) {...}
# .^!clone is used to create a new p6opaque object with the same definitions of the current one.
method ^!clone($object: ) {...}
# .^!DESTROY should be called during the interception of DESTROYALL, after dispatching the DESTROYALL call.
method ^!DESTROY($object: ) {...}


The default "defined" implemented by Object, delegates the call to the representation. By default, an object is defined if there is any instance storage initialized. Which basically means that an object is undefined after CREATE and will become defined after BUILDALL.

# returns if this object is defined
method ^!defined($object: --> bool ) {...}
# makes sure this object is defined (noop for already defined objects)
method ^!define($object: ) {...}
# clean any instance data on this object, making it undefined again.
method ^!undef($object: ) {...}

RW introspection API

Instance data

"instance_storage" is a HoH, where the key in the outer hash is the package. "whence" is the autovivification closure.

method ^!whence($object: --> Routine ) is rw {...}
method ^!instance_storage($object: --> Hash of Hash) {...}

Prototype data

Metaclass instance delegation

method ^!how($object: --> Object ) is rw {...}

Package declaration

method ^!who($object: --> Package ) is rw {...}

OO Hierarchy

The .^!isa here is where the inheritance goes looking. .^!does is only present so ~~ can be made, but the method dispatch doesn't go looking in the roles, the meta should add the methods and attributes of the role into the class when doing the composition.

This is also how a prototype can "lie" about the interfaces it implements, for instance CGI::Simple, could have CGI listed in its .^!does, but it would not go looking for the CGI methods in BUILDALL time.

method ^!isa($object: --> Array of Class ) {...}
method ^!does($object: --> Array of Role ) {...}

Class definition

method ^!attributes($prototype: --> Hash of Attribute ) {...}
method ^!methods($prototype: --> Hash of Method ) {...}
method ^!submethods($prototype: --> Hash of SubMethod ) {...}