[TransWarp] Proposed peak.binding API change

Phillip J. Eby pje at telecommunity.com
Wed Sep 3 10:31:37 EDT 2003

At 11:08 AM 9/3/03 +0300, Niki Spahiev wrote:
>Phillip J. Eby wrote:
>>So, here's my "new new proposal"...
>>binding.requireBinding("what's required")
>>binding.Provide(lambda: expr)
>>binding.Require(doc="what's required")
>>binding.Require(key, offerAs=[key])
>>binding.Require( [key1,key2,...] )
>>binding.Require( binding.delegate("attrName") )
>IMHO i preffer more names (as explicit is better than implicit).

I don't think that more names is always the same thing as being more 
explicit.  It's also Pythonic for an API to take arguments in more than one 
way, to achieve the same effect.  Note that 'max()' and 'min()' will accept 
one argument, or several, and "do the right thing" in either case.  And, 
it's also more Pythonic to have a few highly reusable tools, than a 
proliferation of tools you can't remember.  There are so many binding 
functions that I often don't remember how some of them are called, and I 
wrote them!  To me, that says there are too many.

The irony here is that the current proliferation of names occurred only 
because I basically started with Once, and then kept noticing useful things 
to do with it, and making shortcuts so I could do them without writing 
complicated Once expressions over and over.  Really, *all* of the current 
binding types are just Once, called with somewhat different 
parameters.  There is nothing that any of them do that you can't do by 
calling Once with some set of parameters.  If I had been able to foresee 
the full range of things that Once would be used for, *and* we had 
PyProtocols back when the binding package was first designed, we probably 
would have had only one class for all this in the first place.

>myAttr = binding.Define( ... )

Interesting.  Except that 'myAttr = binding.Define(someType)' doesn't seem 
to make any sense to me.  You're not defining the type.  Note that 
'Provide' (or whatever it ends up being called), always takes one of the 

1. a callable
2. a string specifying how to import a callable
3. a 'default=value' clause.

In none of these three cases does it look like you're "defining" that 
thing.  I suppose maybe you could say you're defining the default, but the 
other two cases occur far more often in our code to date.

There seem to be two distinguishing characteristics of the proposed 
'Provide' class...  First, it is clearly about computing or "originating" a 
value.  Second, it does not establish/document a dependency on other 
component(s).  I chose 'Provide' as the obvious opposite of 'Require', but 
some other possibilities might be 'Supply', 'Factory', 'Produce', 'Invoke', 
'Build', 'Compute', 'Create', 'Originate', 'Origin', 'Source'.

Of those, I'm leaning somewhat towards 'Supply', as it also seems 
complementary to 'Require'.  'Invoke' is strong in the common case, but 
doesn't make much sense for usage #3 (default=value).  'Compute' doesn't 
make as much sense for types, but is good for functions and 
default=value.  'Create' makes sense for types, but not anything 
else.  'Factory' also isn't bad, it definitely covers the callable cases, 
seems a little weird for 'default=value', but maybe we should just use 
'value=' instead of 'default=', and then it makes more sense.

Okay, so as of this point, the leading contenders are 'Factory', 'Produce', 
'Provide', and 'Supply'.  'Factory' has the nice aspect of implying that 
the callable or type you give it will be used as a "factory" to make a new 
value or option.  A factory is also clearly an origin point for a value, 
and it calls to mind the GOF factory pattern, which this may be considered 
a variation of.  The primary downside of 'Factory' is that it seems to 
imply *ongoing* production of values, rather than a one-time 
production.  The other three don't seem to have that implication.

More information about the PEAK mailing list