[PEAK] PeakPlace, Junction

Phillip J. Eby pje at telecommunity.com
Sun Dec 7 22:00:07 EST 2003


At 05:59 PM 12/7/03 -0800, John Landahl wrote:
>On Sun, 07 Dec 2003 19:32:11 -0500, Phillip J. Eby <pje at telecommunity.com> 
>wrote:
>>Part of my point is that it means a Junction is not a reusable component; 
>>you can't e.g. implement multiple junctions in one process with different 
>>configurations.
>
>That's a possibility that I hadn't considered.  My first reaction was to 
>say that you wouldn't want to do that, but on second thought it opens up 
>some really interesting possibilities for much larger applications.

Mutable (aka stateful) singletons are evil.  Really, truly, evil.  (Because 
how many of a thing you have is a policy decision, not a mechanism.)  About 
the only thing I really actually dislike about twisted is its insistence on 
the use of singletons, especially the reactor.  Thus, my first reaction to 
a singleton is always to question it.  Usually, this does open up 
interesting possibilities, although not necessarily from the first moment.

Anyway, there's a very good reason why 'binding.Component' and 
'binding.Singleton' in PEAK don't mix.  :)


>>* Never instantiate a component as the default value of a binding.Make; 
>>this will not work correctly if there is more than one instance of your 
>>class.  (If there really is only one instance, make it a singleton; but 
>>that's usually only sensible if it has no state.)
>
>Where did you see this happening?

The junction class has two Obtain() calls that have default=someObj().  I 
misinterpreted them as component instantiations, (and mistakenly called 
them Make calls) -- sorry.  If it were me, I'd make the ServiceLocator a 
binding.Singleton (since it's stateless), so there'd be no need to 
instantiate it.  And I'd set a "constant" to dnsUUID() near the top of the 
module, then refer to it in the default.  Thus, I wouldn't be distracted by 
the apparent creation of components in the defaults.  (Heck, I'd probably 
export a defaultUUID from the util module, and then import that for use as 
the default.)

Of course, I'm probably just paranoid and superstitious, here.  But I 
definitely wouldn't want to give somebody else the impression that 
constructing a possibly mutable object as the default for an Obtain() 
binding is a good idea.

Hm.  I wonder if it would be useful to allow configuration keys to be 
unioned?  That is, if you could do, e.g.:

      thing = binding.Obtain( IServiceLocator | 
"import:junction.util.ServiceLocator" )

That is, first try to find an IServiceLocator, then fall back to importing 
the default.  Interesting.

In practice, it would probably need to be a class or function, like 
'config.OneOf(IServiceLocator, "import:...")', because most of the types 
used for configuration or component keys aren't going to support the right 
meaning of '|'.  But it might get rid of the need to even *have* a default 
value for Obtain, if coupled with say a 'config.default'.

I imagine it would be a good idea for me to think some more about this sort 
of component key, config key, or recipe "arithmetic".  There do seem to be 
some common patterns floating about.

One other thought that's been on my mind lately is whether PEAK really 
needs to separate the 'binding' package into 'binding' for attributes, and 
a separate 'components' package for the component/hierarchy stuff.  There 
are probably also a couple of config items that might move to 'components' 
in that case.

Here's why.  For explanatory purposes, I talk about "bindings" a lot, in 
ways that imply they are only attributes (Make, Obtain, Require, 
Delegate).  But, there are a bunch of other binding API's that are really 
*component* APIs.  Like lookupComponent, IComponentKey, and so on.

This is probably going to annoy the folks who just asked for a 'core' API, 
since now there'd be two things being imported where one previously 
sufficed.  As I see it, we'd end up with:

binding: Make, Obtain, Require, Delegate, classAttr, IActiveDescriptor, 
IBindableAttrs, IRecipe (plus getInheritedRegistries, supertype, 
Descriptor, Attribute, AttributeClass, Activator, and ActiveClass)

components: lookupComponent, getParentComponent, getComponentName, 
suggestParentComponent, getComponentPath, getRootComponent, 
notifyUponAssembly, Singleton, Component, ComponentName, IAttachable, 
IBindingNode (needs a new name), IComponent, IComponentFactory, IComponentKey,

During a transition period, the 'components' API would also be available 
under the 'binding' namespace.

Now that I've actually proposed it, I do see some problems with it.  My 
main intent is to group things in chunks that allow sensible 
explanation.  One of my big problems trying to write the original tutorial 
is that the ideas contained under the heading of 'binding' were extremely 
broad.  Still, I'm not sure the split would help that much, because the 
concepts *are* rather intermingled.  Certainly the implementation of both 
packages would still be deeply tangled.  Hm.

I suppose the thing that I really want to accomplish is find a way to add 
convenient utilities like the 'oneOf' thing, and not have them confused 
with actual bindings like Make and Obtain.  Thus, one could Obtain( 
oneOf(...) ) and have it be clear what was going on.

Sometimes, it seems to me that there is an even simpler concept inside of 
the binding and naming packages, that's still struggling to get 
out.  Probably it's just that I want recipes and component keys and all of 
those things to be composable, via things like the oneOf() idea or the 
current naming.Indirect().  Using lambda: or functions to do things in 
bindings nearly always seems klunky to me, when they're things that you do 
over and over again.

Ah well.  Probably I'll just go through in a4 and re-sort where the code 
lives in the binding package, so that everything's in reasonable 
places.  Maybe make 'adapters' modules in binding and config to hold their 
respective adapter classes, just like there are 'interfaces' modules for 
interfaces.

Anyway, this is all rambling and largely unrelated to your post, so I'll 
stop now.  :)





More information about the PEAK mailing list