[PEAK] And so it begins... (generic function migration)

Phillip J. Eby pje at telecommunity.com
Thu Nov 11 00:07:11 EST 2004

Here are some current candidates for potentially switching from interfaces 
to single-dispatch generic functions:

* binding.IComponentKey -- findComponent()
* binding.IAttachable -- setParentComponent()
* binding.IBindingNode -- getParentComponent(), getComponentName()

* config.IStreamSource -- getFactory()

* naming.IBaseURL -- joinURL()
* naming.IReferenceable -- getReference()

* net.IClientSockAddr -- connect_addrs()
* net.IListenSockAddr -- listen_addrs()

* running.ICheckableResource -- checkResource()

* security.IAuthorizedPrincipal -- checkGlobalPermission()
* security.IPermissionChecker -- checkPermission()
* security.IGuardedObject -- getPermissionForName() [full GF?]

* web.IViewTarget -- registerWithProtocol()

* Virtually all peak.model interfaces [full GF's]

* running.IExecutable and friends

This is a preliminary list, and some items on it might get 
eliminated.  Essentially, these are interfaces that are "stateless", where 
the interface usually doesn't inherit from another interface, nor do other 
interfaces inherit from it.  Also, the interfaces are usually mostly 
implemented as adapters, rather than as methods of the target 
classes.  Often, the functionality is accessed via an existing functional 
API such as 'binding.getParentComponent()', or could be.

Currently, my thought regarding these is to start with the most recently 
introduced items: config.IStreamSource and naming.IBaseURL.  Also, 
naming.IReferenceable isn't actually used in the core currently, so it 
should probably just be deleted!  (Assuming nobody's using it out there.)

I'd like to then do the 'binding' interfaces, because they are all backed 
by API functions already, and don't appear to be used outside the 
core.  I'm wavering a bit on IComponentKey, though, because 
'lookupComponent()' supports 'adaptTo' and 'suggestParent' operations that 
would have to be duplicated in each method of a 'lookupComponent' generic 
function.  On the other hand, creating a 'findComponent()' generic 
function, that's then used by 'lookupComponent', would also work, at the 
cost of having another visible API.  Then again, in the long run, it'll be 
balanced by one less interface.

There is of course the question of whether some of these are even worth 
touching.  I have strong, concrete use cases only for IAttachable, 
IBindingNode, IStreamSource, IBaseURL, and the model, security and web 
stuff.  I have some vague use cases for the 'running' stuff.

So I guess that sums up the priorities, at least for single-dispatch 
stuff.  I'm not sure if I'll actually migrate the security stuff to 
single-dispatch as a first step, or just go straight for multi-dispatch, 
which we *really* need in order to have decently reusable security metadata 
and rules.

In separate posts, I'll start laying out more detailed designs for how 
we'll start implementing general metadata for classes and their attributes 
using generic functions, and specific plans for refactoring peak.security 
to use generic functions, and peak.binding to allow general annotations to 
be supplied as part of attribute bindings.  peak.web will also have its 
view system refactored to use full generic functions, and site maps will 
add an attribute to allow you to specify conditions on views, so that e.g. 
you can say, when account balance is less than some amount, show this view, 
otherwise show this other view.  (Or, "if user is logged in, show the 
welcome box, otherwise show the login box".)

Somewhere in the midst of all this, I'll be writing the peak.model 
replacement, tentatively called peak.schema.  The schema package will 
basically re-implement what's in peak.model now, but using separate 
metadata "aspects" to handle security, parsing, CORBA info, relationships, 
etc.  The core of peak.schema will thus be quite simple: mostly simple 
attribute descriptors plugged into generic functions that are methods of a 
workspace object.  (With a default "null workspace" object for objects used 
outside a workspace.)  By subclassing the basic workspace and adding 
metadata or new methods, you'll be able to completely customize the 
behavior of objects created and used in that workspace, including custom 
validation constraints and the triggering of arbitrary actions in response 
to changes in model objects.  Er, schema objects.  :)

Some of these features will require sophisticated method combination for 
generic functions, as I laid out in a previous post here.  So, at some 
point I'll have to go back to add those.  (peak.web will need those 
features also at some point, in order to do menus.)

While peak.schema is being built, peak.model will remain as-is.  That's 
because peak.schema isn't going to support all of peak.model's features 
initially.  For example, I'm unlikely to focus on syntax (parse/format) at 

Once enough of the schema stuff is there, I'll go back to working on the 
"workspace" concept I posted a few months ago, using generic functions to 
help implement many of the hairier bits that I've been avoiding to 
date.  The workspace concept will actually be the culmination of a big 
piece of the original vision for TransWarp: backend-specific "markup" of 
domain model classes to implement an efficient mapping to any storage 
mechanism, be it in-memory or in-database, while still being able to 
customize and override aspects of the mapping for a specific application.

Exciting days are ahead!

More information about the PEAK mailing list