CMFContentTypeDesign

CMF content type design

The CMF content types will be merged with the content model by creating specialized interface objects that are easly persisted. They will be largely equivalent to existing CMF portal types in that they are not much more than a name. They will not contain meta data. Meta data will be managed elsewhere, such as in a portal types tool. A significant difference from existing portal types is that CMF content types will explicitly derive from pther types. This means that components usable with base types will be usable with the derived types.

A key risk is in the persisting of type references. An object that asserts that it implements a type will need to store the assertion persistently as part of it's state. We have two choices when storing the interface assertion:

  • We can store named interfaces directly by value
  • We can store interfaces by references

For interfaces created in Python modules, we can store interfaces by reference. For persistent interfaces, storing by reference requires special handling. If a simple persistent reference is used, then the interface will be copied wheever the object is copied. If a named reference is used, then a name registry needs to be maintained, which adds a lot of complexity.

An alternative is to store persistent interfaces by value, where the value is the interface name and a sequence of base interfaces. These interfaces cold contain no other information. Two persistent interfaces would be considered equivalent if they had the same value (name and base interfaces).

A variation on this theme is to have a way to say that an instance implements some interface in addition to the interfaces that it's class asserts that it implements. In this way, we could change the class-provided contracts by modifying the class.

We could take this last step a bit farther and say that if a string is provided where an interface is expected, then it is equivalent to a marker interface with no base interfaces.

Puting this all together I propose that we define marker interfaces:

  • A marker interface is specified by it's name ans base interfaces.
  • A marker interface is persistented (pickled) as a name and a set of base interfaces.
  • Marker interfaces are equivalent of their name and bases match. That is, they are compared by value, rather than by identity. They are hashed based on their name.
  • The component architecture needs to perform equality rather than identity comparisons. Methods of non-marker interfaces might still take advantage of indentity comparisons, but, I suspect that we can create a C implementation of interfaces that makes equality comparison of non-marker interfaces more or less as fast as identity comparison.
  • I'd like to come up with a representation for interface assertions that specify that an object implements some interfaces in addition to the interfaces asserted for instances of it's class.


hathawsh (Jul 17, 2001 4:48 pm; Comment #1)
I think the complexity of an interface registry should be avoided.

As I understand it, when an object is created based on a CMF type, it will be assigned an __implements__ attribute expected to remain unchanged for the object's lifetime. Note that during the object's lifetime, the meaning of the CMF type can change or even be removed. The interfaces supported by the object's class may also change.

I envision a creation process something like this:

  content_type = 'News Item'
  ob = newsitem_factory()
  ob.__implements__ = ContentTypeImplements(content_type)
  container._setObject(id, ob)

ContentTypeImplements is a class.

Note that the seating of the object occurs outside the factory. I think this is more sensible since it removes dependence on the name _setObject from factories and permits unseated objects to be created.

Now consider what will need to happen for the Interfaces package to see the ContentTypeImplements instance and figure out what interfaces are supported.

If we want to assume that all content objects are ExtensionClass instances (which is the case today), we have an interesting but maybe obscure option. Similar to PermissionRole, ContentTypeImplements could provide an __of__ method that returns a tuple containing the marker interface and the interfaces supported by the class. This would probably work well. The Interfaces package wouldn't have to change--it would only see the tuple.

If we want to try to remove ExtensionClass assumptions, we could get the Interfaces package to call anything that's callable when looking at the __implements__ attribute, passing the instance as the only parameter. (Without the parameter, the instance would have no way to know what its parent is.)

Either solution provides the same flexibility for dynamic interface assertions.

hathawsh (Jul 19, 2001 2:34 pm; Comment #2)
Okay, after discussing this further with Jim, we decided that ob.__implements__ would contain a string and a marker indicating that the instance should inherit the interfaces of its class. For example:

ob.__implements__ = ("News Item", CLASS_INTERFACES)

The Interfaces package will look up the interface corresponding to the name "News Item" through a ComponentArchitecture function. The lookup may be placeful.

We chose this because it is more likely to be optimizable.



( 95 subscribers )