[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.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