Author: allison
Date: Fri Sep 14 13:14:02 2007
New Revision: 21293

Modified:
   trunk/docs/pdds/draft/pdd17_pmc.pod

Log:
[pdd] Radical simplification for inheriting from low-level PMCs in high-level 
classes.


Modified: trunk/docs/pdds/draft/pdd17_pmc.pod
==============================================================================
--- trunk/docs/pdds/draft/pdd17_pmc.pod (original)
+++ trunk/docs/pdds/draft/pdd17_pmc.pod Fri Sep 14 13:14:02 2007
@@ -148,7 +148,7 @@
   pmclass <name> <modifiers> {
   }
 
-The modifiers specify core features such as:
+The modifiers specify core features, such as:
 
 =over 4
 
@@ -178,7 +178,7 @@
 =item no_ro
 
 Don't create a second read-only vtable for the PMC. (Used, for example,
-by STMs C<share_ro()>.)
+by STM's C<share_ro()>.)
 
 =item is_shared
 
@@ -193,13 +193,16 @@
 
 Compose a role. Takes one argument, the name of the role to compose. [NOTE:
 this modifier has been taken from the older feature C<does> which is now called
-C<provides> (fulfills|supplies|satisfies).]
+C<provides>.]
 
 =item 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 C<does> may also define C<provides> for one or more
+interfaces.
+
 =over 4
 
 =item * C<array> is an aggregate PMC with numerically-keyed elements
@@ -243,16 +246,20 @@
 The standard way of declaring attributes is with C<ATTR> within the body
 of a C<pmclass> or C<prole> declaration.
 
-  ATTR <type> <name> [:<modifier>];
+  ATTR <type> <name> [ :<modifier> ... ];
 
 This declaration is used to generate the data struct for the PMC
-(named "Parrot_<pmcname>_Data"), including any attributes declared in a
-composed role.
+(named "Parrot_<pmcname>_Data"). The data struct incorporates any
+attributes declared in a composed role. The declaration is also used to
+generate accessor macros for the class, in the form of
+GET_ATTR_<attrname> and SET_ATTR_<attrname>, and to set up helper
+information for the C<inspect> vtable function, and to provide attribue
+access throught the default C<get_attr> and C<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.
+compose roles, and in PMCs that will be subclassed by high-level classes
+(this means all core PMCs, and most non-core PMCs).
 
 =head3 Defining vtable functions
 
@@ -300,11 +307,12 @@
 =head3 Methods
 
 Methods are declared in the body of the C<pmclass> or C<prole>
-declaration with C<PCCMETHOD>.
+declaration with C<METHOD>.
 
-  PCCMETHOD inspect(STRING *what :optional, int got_what :opt_flag) {...}
+  METHOD inspect(STRING *what :optional, int got_what :opt_flag) {...}
 
-[NOTE: There is also an older C<METHOD> keyword, which is deprecated.]
+[NOTE: There is an older C<METHOD> keyword, which is deprecated. The
+current C<PCCMETHOD> will be renamed to C<METHOD>.]
 
 =head2 PMCs and Namespaces
 
@@ -342,13 +350,14 @@
 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 may not 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.
+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 C<prole> keyword. 
 
@@ -359,23 +368,25 @@
 
 Role attributes are defined using the same format as PMC attributes.
 
-Core roles live in src/pmc along with the core PMCs, but they have a file
-extension of C<.pr>.
+Core roles live in src/role and have a file extension of C<.pr>.
 
 Roles are composed into a PMC with the C<does> modifier.
 
-=head2 Interaction between PMCs and high-level objects
+=head2 PMCs and high-level objects
 
-High-level objects, as specified in PDD15, need to be able to inherit from
-PMCs. This is achieved through the combination of a C<PMCProxy> PMC and
-delegation.
-
-For PDD15 objects, there is a corresponding instance of the C<Class> PMC. For
-a PMC, however, the class definition is written in C and compiled away. There
-needs to be something that can be placed in the parents list for a PDD15
-class. That something is the C<PMCProxy> PMC. Like a PDD15 class, it is
-stored as the C<class> element in the namespace associated with a PMC, provides
-introspection facilities and can sit in an inheritance hierarchy.
+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 C<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 C<PMCProxy>
+PMC. Like a PDD15 class, it is stored as the C<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
@@ -394,69 +405,49 @@
   $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 get
-a chunk of state that it can use as it wishes. Further to this, if multiple
-PMCs are inherited from, they may use the state in different ways. Users of
-Parrot at a PIR level should not have to care about such issues.
-
-(AR: I'm willing to make some changes in how low-level PMCs store state in
-order to make this easier.)
-
-Therefore, when a PDD15 object is instantiated and it inherits from PMCs, an
-instance of each of the PMCs that it inherits from is also created. These are
-stored at the end of the object's attributes store.
-
-When a method is called on an object whose class has PMC parents, the call is
-delegated up to each of the PMC parents, in MRO order. The invocant must be
-the appropriate PMC instance from the object's attribute store. For v-table
-calls, this is just a case of passing the correct thing. For other methods
-that are located by C<find_method>, a C<Bound_NCI> PMC is used to ensure that
-the method from the PMC is invoked with the correct instance, so it has access
-to the correct state.
-
-(AR: Why isn't it called directly on the delegated PMC stored in the delegating
-object's data store?)
-
-When a PMC calls a method on itself, it may have been overridden in a high
-level class. Therefore dynamic dispatches of method calls need to be done with
-the vtable of the high level class, not the vtable of the PMC itself.
-
-For PMCs that are instantiated and not overridden, the C<real_self> pointer in
-the PMC structure is a reference to the PMC instance itself. If, however, it
-is just acting to provide the state a PMC needs but is not the real instance,
-this pointer will point to the instance of the high level class (an instance
-of the C<Object> PMC). Method dispatches using C<DYNSELF> will always go
-through this mechanism.
-
-(AR: See comment above about delegated calls. Better to have the delegator
-object only exist for delegated PMCs, and have DYNSELF check for it.)
-
-Attribute access is, like method access, delegated upwards. Since attribute
-lookup is a vtable method, the down case is covered by the previous paragraph.
-
-(AR: What about overriding a low-level attribute with a high-level attribute?
-Can you override the core data store of a Hash? The core struct members of an
-STMLog? This would be a lot easier if low-level PMCs had a standard way of
-defining their attributes (core struct members), which could be used to
-generate struct declarations, to automatically fill a PMC's C<inspect>,
-C<get_attr>, and C<set_attr> vtable functions, to annotate PMCProxy objects,
-and to allow state for compile-time roles to be generated in the same struct as
-state from the PMC 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 a standard interface. It
-must implement the C<get_attr> and C<set_attr> vtable entries for any core
-attributes it expects to be accessible to subclasses.
-
-Subclassing a low-level class from a high-level class makes an entry in the
-high-level class's list of parents. This entry is a proxy class object for the
-low-level PMC class that provides access to the low-level PMC's vtable
-(including the implementations of get_attr and set_attr), and defines the
-storage that the low-level object will need within the high-level object (this
-could be as simple as a single integer attribute that gives an index into the
-object's data store where an instance of the low-level class is stored).
+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 C<ATTR> in the declaration body of the low-level PMC, as
+if each had been added with C<add_attribute>. It will also override the
+C<GET_ATTR_attrname> and C<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
+C<METHOD> and insert them in the proxy class as if each had been
+declared with C<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.
+
+(This will likely require changing the C<SELF> shortcut to be equivalent
+to C<DYNSELF>, which is what it probably should have been in the first
+place. We can create an alternative C<STATICSELF> for the rare cases
+when we really need it.)
+
+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.
 
 
 =head1 REFERENCE

Reply via email to