# this is the runtime meta object protocol # it is completely decoupled from the compile time meta object protocol # this document does not describe how objects/classes etc are defined, but # rather how they interact with other objects, and calling conventions within # the context of a runtime. # all the role/class names in this document are subject to dyslexia, and future # rechristening ;-) # SECTION 1 # dispatch - where in all is explained about invocations role Invocation { # anything that agrees with a ResponderInterface of some sort # an instance of an invoction is a descriptor for a call. # the class of an invocation is it's calling convention # for example SimpleNamedInvocation is a dispatch using method names # the calling convention is that of named methods # the descriptor contains the method name to invoke # these objects are constructed as a result of the syntax the user typed in. # a domain specific language or subfeature, or explicit meta-invocation may # introduce new types. # Perl 6 supports these invocations natively: # code references over a single invocant (class or object), # named single methods over a single invocant or an invocant bundle # fully qualified methods over a single invocant or an invocant bundle # rule invocation over a grammar/match # multisubs over a global registry? ~Y~Y~Y~Y~ } role ResponderInterface { # anything that agrees with an Invocation of some sort method invocation_body ( Invocation $inv, Responder $whatever ) { # invocation is a method, multimethod, whatever # as long as the responder interface knows what to do with it # responder interface is a interface-value of an instance. Perhaps the # polymorphic, encapsulated equivalent of a vtable is a good description. # this may be a runtime value. # a responder is a front for an instance } } role Runtime { method responder_interface_for( Responder $inv --> ResponderInterface ) { ... } # the responder interface is (theoretically) an external attribute of an instance # or other invocant-ish entity, and may be carried alongside it, inside it, # in it's boxed form.... whatever # the runtime must *somehow* know to find the right responder interface for a given # responder. how it does that is unspecced, and runtime dependant # conversely, an Responder is anything the runtime can find a ResponderInterface for ;-) # more intricantly, a responder is any value that can take the invocant # role, assisted by it's ResponderInterface } role Responder { # as mentioned earlier, a responder can be: # an invocant in SMD # an invocant bundle in MMD # a class for class method dispatch # anything else that can accept dispatches } role InvocationBody { method bind (...) { # invocants and arguments in some sort of signature object # this method is between the body implementation and the runtime, and # they alone decide on it # for example this method may accept thunk bodies, returning a template # thunk to be filled in or whatever, when performing static dispatch # this method may simply do the runtime binding, returning a thunk on # real values } } # two responder interfaces and three calling conventions class MethodTableInterface { # this is a method *definition* class SimpleMethod { has InvocationBody &.body; # of some sort that the runtime can execute } has SimpleMethod %methods; # invocation body is a multimethod # a responder interface can support any number of calling conventions. # For simplicities sake this might actually not be a multimethod, but a # dispatch table of some sort. # dispatching code refs on an invocant just invokes the code ref # this should probably be a base method of ResponderInterface::Perl6::Base # ot some other base role which knows about Perl 6 code types. multi method invocation_body ( CodeRefInvocation $inv, Responder $inv ) { # Repsonder should probably be SMDResponder, which is a role that both ClassBasedObject and Class do return $inv.body; } # dispatching a named method on an invocant finds # the body of the method in the responder interface multi method invocation_body ( SimpleNamedInvocation $inv, Responder $inv ) { %.methods<$inv.name>.body; } # fully qualified method invocations are invocations which *should* happen # on another responder interface. # however, the responder interface is god, and it gets to decide what # happens to the object on a local level. # in this case it chooses to be nice: multi method invocation_body ( FullyQualifiedNamedInvocation $inv, Responder $inv ) { $inv.responder_interface.invocation_body( $inv ); } # this is also a likely candidate for a base role } class PrototypeInterface { # this meta responder interface delegates most decisions to the invocant # this is the same as the definition above multi method invocation_body ( CodeRefInvocation $invocation, PrototypeObject $invocant ) { return $invocation.body; } # this is the same as the definition above # class objects and prototype objects can share the calling convention of simple named methods multi method invocation_body ( SimpleNamedInvocation $invocation, PrototypeObject $invocant ) { return $invocant<$invocation.name>.body; # just search inside thew invocant } # like the above definition we can be nice about it # in truth, we might want to actually let the instance itself take care of this # it doesn't really matter since this is just an example multi method invocation_body ( FullyQualifiedNamedInvocation $inv, PrototypeObject $inv ) { $inv.responder_interface.invocation_body( $inv ); } } # the below invocation types are heavily simplified # they cannot, for example, describe arguments yet. # in Perl 5: # my $code_ref = sub { }; # $obj->$code_ref() class CodeRefInvocation does Invocation { has InvocationBody &.body; } # in Perl 5: # $obj->foo(); # or # my $method_name = "foo"; # $obj->$method_name(); # this is a call-method-by-name invocation descriptor class SimpleNamedInvocation does Invocation { has $.name; } # in Perl 5: # $obj->Foo::Bar::method(); # this is a call that the user already preresolved to a certain responder. # proboably by referring to some class. class FullyQualifiedNamedInvocation does Invocation { has $.name; has $.responder_interface; } # Here is the meta-method calls that the runtime must invoke to deliver an # invocation to an instance. # it is pseudo-code that a runtime that uses boxed types might implement: $instance_box.responder_interface.invocation_body($invocation, $instance_box.value).bind( $instance_box.value ).invoke(); # ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # | | # assuming boxed types of some sorts this is probably a single runtime opcode # it is mediated between the InvocationBody # and the runtime # For example, for the following construct: $obj.foo(); # the above code is compiled to the following pseudocode. This is followed by # an annotation of how a partial-evaluation strategy may be used to reduce the # meta-ness out of everything. $foo_box.responder_interface.invocation_body( SimpleNamedInvocation.new( :name("foo") ), $foo ).bind( $foo ).invoke(); # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^ # | | | # this might be constant this is probably a constant runtime dependant # folded if the class is # statically known at # compile time # # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # | # if all the components of the invocation body can be statically known # then the whole invocation body can be constant folded into a simple structure. # this is feasable if invocation_body ignores the Responder parameter. $hard_coded_body.bind($foo).invoke(); # or more familiarly $hard_coded_body.( $foo ); # at which point $foo_box can be optimized away # similarly, if $hard_coded_body can be inlined, or even proven constant over # $foo by means of partial evaluation, all is fair game. # the "meta" invocations are also completely cascadable, as long as you compile # the compiler with the appropriate meta meta classes ;-) # the compiler is, of course, bootstrapped with core Perl 6 OO, to get around # the cyclic issue. # SECTION 2 # types are just methods # Type information about a certain object is encapsulated within it's ResponderInterface # the notion of types is in fact delegated by this object to the underlying meta model. # the dispatch of e.g. $obj.isa(Dog); # is a true method invocation (although the method may not be a part of class # of $obj per se, it's meta class may have compiled a responder interface to # include it). # these methods are to be implemented in such a way that the compiler knows go # about infering about them, and must typically resolve to an inlinable # operation which discludes the $obj's actual value. # however, in a full prototype-object system, every object is also it's own # responder interface in a way # the runtime or compiler may demand certain type related information to be present # furthermore they may even demand that these methods do not actually depend on # the invocant, under static type checking modes. # this is not a part of the object protocol though, it is just a compile time # usage of said objects in a certain way. # SECTION 3 # AUTOLOAD and friends (engaging in promiscuouos behavior, while practicing safe sex) # these are just nits of the ResponderInterface # should it choose to present a certain InvocationBody based on the value of the responder. # For an example of an implementation stragegy see PrototypeInterface # a method of an invocation interface may look something like this: method invocation_body ( SimpleNamedInvocation $invocation, Responder $invocant ) { return %methods<$invocation.name>.body || %methods.body.assuming( :method($invocation.name) ); # assuming is a hypothetical method that this responder interface's method definitions know to implement. } # this is a secret that ResponderInterface keeps to itself - the runtime need # never know that it doesn't *really* handle those methods ;-) # SECTION 4 # Instance layouts - the other side of the runtime # The layout of an instance is completely opaque, and is a contract between the # runtime and the instance, much like ResponderInterface is. # the only difference is that the constructor methods of a certain class need # access to this layout object in order to generate additional layouts. # Meta layout objects are used by the compile time object protocol to construct # a layout generator of some sort. Supposedly this meta layout generator is a # chunk of invocable code much like the chunk InvocationBody encapsulates. # A runtime may impose a necessity for the layout generator to be of a certain # subclass. for example, a runtime over the perl 5 virtual machine will want # all layouts to be somehow SV based. A runtime abstraction over the parrot vm # will like magic cookies. # This is completely opaque, and in truth just a delegate of the class, invoked # in the constructor, that is bootstrapped to return a native type. # for convenience purposes, meta layouts with string based slots, array of # string based slots (namespaced), and index based slots will be available # for the Moose/perl5 backend the will be a hash based layout generator for the # slot based meta layouts, an array based layout generator for index based meta # layouts, and inside out layout generators for both types. Meta layouts could # be infact composite meta layouts, containing e.g. both indexes and slots, by # simply constructing a weird layout genreator. # all instance data access is, like the layout generator, emitted by the meta # layout. However, this emission is probably handled by the same deleage that # was used to implement the layout generator (hash, array, inside out). # the calling convention of these items is opaque, and the method bodies must # simply know how to handle them. # they may objects, code references, inlined macros, or whatever. # meta layout: slot # layout meta generator: hash, array, inside out # layout geneator: the construct_instance method # layout accessor: instance data handling # SECTION 5 # Vtables are how ResponderInterface and Runtime became the best friends ever # To implement vtable like structures, a ResponderInterface simply creates a # projection of itself into a Vtable. # in this case VtableResponderInterface is a role that ResponderInterfaces can # do, and the current runtime seems to care about. if $responder_inferface.does(VtableResponderInterface) { $index = $responder_interface.invocation_index($invocation, $instance); # let the responder interface translate the meta invocation into a native type $responder_interface.vtable_for($instance)[$index].bind($instance).invoke(); } # where vtable_for is an inlinable operation, that traditionally is the return # value of following a pointer in the instance. # if the invocation_index method doesn't rely rely on $responder_interface (and # it better not - all methods are mangled to indexes in a central table # specific to the uppermost type of $instance (probably just Any, in which # case the vtable is as wide as all the method names registered)), then $index # can become a constant. # in situations where vtable_for($instance) does not rely on $instance, but # only on it's uppermost type, the vtable is inherently constant, and thus non # virtual dispatch is achieved for that type. # if the least derived possible type of $instance has *not* been declared, then # there is probably some vtable clash, and the vtable will be consulted much # like a C++ virtual method. # Note: wherever $instance is mentioned in this document, this is actually a # magical value during partial evaluation, that will respond to certain # methods, for example, to determine the upper most type, for the sake of # constant folding # to simplify things, the protocol has been designed such that expliciit # partial evaluation can be effectively used to optimize it into a static # dispatch model. # This is to retain the pure definitions of the various interfaces # (optimization is a cross cutting concern) without losing the potential for # fully static dispatch. # the exact semantics of the the magical # $junctive_instance_during_partial_evaluation are yet to be resolved. # Responder may have a richer interface in the future to compensate for this.