On 6/29/09 4:49 PM, Ross Patterson wrote:
Wichert Akkerman<[email protected]>  writes:

I am just catching up on Ross's work last week, and I am not sure
about the changes in this changeset:

http://dev.plone.org/old/collective/changeset/88642/Products.membrane

This changeset was proposed and discussed well in advance.  It would
have been vastly preferable to bring up debate *before* a contributor
put the time in to implement.

I was not aware of it. I looked a while ago and could not find a membrane mailinglist anywhere, so I don't think I can be blamed for that. Even today there is no mention at all in the membrane package that the remember list is used for membrane development.

I see the problem Ross is trying to solve: generating a list of
everything an object can be adapted to is expensive (which is why the
same thing was removed from the Plone 3.x tree just before 3.0).

This solution moves the penalty to the developer: instead of only
having to write an adapter developers are now forced to register both
an adapter and a new marker interface. I feel quite strongly that this
repetition is not desirable, so I want to investigate alternatives.

If by "register" you mean the "<interface>" registration, the developer
would not need to do that.  All the developer would need to do is make
sure the class implements the marker interface which can be done in the
class level implements declaration or in ZCML.  This is one of the most
simple declarations possible.

Sure, but my point is that this shoudl not be necessary. Why should we force developers to both register a marker interface and an adapter? That is the kind of extra repetition and extra work that we are now working hard on removing from Plone.

A trivial alternative is to add some simple caching to the
object_implements method. If we cache based on class and directly
provided interfaces we should get the exact same results while having
almost no noticeable performance problems. This might even allow us to
simplify the code and only use the slow-but-readable code path

I don't think caching should be used to solve a problem where code is
doing too much.  In this case, I think this is a matter of explicit
vs. implicit.  The previous implementation was implicit, tried to do too
much, and it's performance problems stemmed from its implicitness.  I
think an explicit implementation is better than a caching implementation
that tries to do too much and then hides that fact.

I agreed, which is why I prefer the custom indexer option.

Consider someone who builds a sub-typing membrane implementation where
content has interfaces applied to individual member content that results
in those object then *becoming* adaptable to one of these interfaces.
With a caching solution, we require them to invalidate the right cache.

It won't in this case actually, since the directly provided interface would be part of the cache key. Managing behaviour via marker interface is quite common, so I did think of that one :)

Plone offers a fairly rich system of catalog indexing helper routines
which we can leverage. Instead of iterating over the ZCA registrations
to build a list of interface an object implements or can be adapted to
we can do simpler things. For example we could have a feature catalog
that looks like this:

With the current implementation, we don't iterate over the ZCA
registrations, we lookup interfaces that have been registered as
providing the IMembraneQueryableInterface.

@indexer(Interface, membrane_tool.IMembraneTool)
def features(obj):
     _features = dict(user = IMembraneUserObject,
                      auth = IMembraneUserAuth,
                      props = IMebraneUserProperties)

     result=[]
     for (ft, iface) in _features.items():
         a=iface(obj, None)
         if a is not None:
             result.append(ft)
     return ft

This should be fast enough for indexing purposes since we can use all
the fast paths and optimisations from the ZCA, and gives us much
simpler catalog data: we will no longer need to index all the
interfaces that are not relevant for membrane. There is an obvious
optimization here: if an object does not adapt to IMembraneUserObject
we can short-circuit and stop processing immediately.

But it is not as easily extensible.  With the interface utilities
approach, used in zope 3 in several places BTW, it's much easier to add
"features".

Why is it not as easily extensible? Because we rely on that feature list there? I do not see that as problematic, since the only way that can be extended is by adding support for new features to the membrane code anyway, at which point you could easily add extra items here. And you can always use a custom indexer if you require more advanced customization.

Wichert.





--
Archive: 
http://www.coactivate.org/projects/remember/lists/remember/archive/2009/06/1246287477932
To unsubscribe send an email with subject "unsubscribe" to 
[email protected].  Please contact [email protected] for 
questions.

Reply via email to