[Zope3-dev] Re: Interface declaration API

Guido van Rossum guido@python.org
Wed, 12 Mar 2003 18:10:14 -0500


> While on this subject, can you or someone else involved with the original 
> proposal explain why it's useful to have mutable interface specs, 
> anyway?  Is there some highly motivating use case for having interface 
> specs be able to be lvalues?  Otherwise, it seems much cleaner to me to 
> have API functions to do the manipulating.  That is, 
> 'implementedBy(Foo).add(IBar)' would be 'addImplements(Foo, IBar)'.

Wasn't me (I'd prefer the latter to spell this), but I'd say that the
latter would probably have to be made equivalent to the former (or its
moral equivalent) anyway.  I.e. (I don't know how you actually spell
that an interface specification contains a given interface, so I am
making up notation using 'in'):

  x = implementedBy(Foo)
  print IBar in x		# False
  addImplements(Foo, IBar)
  print IBar in x		# True



> >>With descriptors only, you are powerless to do this to anything that 
> >>doesn't have the descriptor already present.
> >
> >When you need one, you can add one. For example:
> >
> >   classInstanceInterfaces(Foo).set(IFoo)
> >
> >would add a descriptor to Foo.
> 
> Why is this more desirable than say, 'setImplements(Foo, IFoo)'?
> 
> > > Data descriptors take
> >>precedence over what's in __dict__, and this can make metaclass access 
> >>"weird".  Example:
> >>class Meta(type):
> >>    aProp = property(...)
> >>class Class(object):
> >>     __metaclass__ = Meta
> >>     aProp = property(...)
> >>ob = Class()
> >>In the above code, accessing 'ob.aProp' will call the __get__ of 
> >>Class.__dict__['aProp'], but accessing 'Class.aProp' will call the 
> >>__get__ of Meta.__dict__['aProp'].  This means that you can't just write 
> >>a '__get__' that looks to see whether it's being called on the instance 
> >>or the class in that case.
> >
> >Why not?  In both of the cases you've mentioned, we know we are being called
> >on the "instance" as far as the descriptor is concerned.
> 
> Right, but the descriptor *itself* cannot be the bearer of the data, 
> because the metaclass descriptor won't know the instance's content.  That 
> is, Meta.aProp cannot know what value Class.aProp should have without 
> consulting some other data present in Class.  So, you have to have two 
> attributes: the "real" attribute, and the descriptor that either computes 
> or returns the value of the "real" attribute.  But this is implementation 
> detail.
> 
> 
> >>Actually, by having InterfaceSpecification instance simply keep a set or 
> >>dictionary of the declared interfaces and have a __contains__ method that 
> >>delegates to the dictionary, you wouldn't need an explicit cache:
> >>def isImplementedBy(self,ob):
> >>     return self in implementedBy(ob.__class__) or self in 
> >> directlyProvidedBy(ob)
> >
> >That doesn't work, because you need to do extends checks, not just sameness
> >checks.
> >
> >Consider:
> >
> >   class I1(Interface): pass
> >   class I2(I1): pass
> >
> >   class C: implements(I2)
> >
> >   I1.isImplementedBy(C())
> >
> >The answer needs to be true, even though I1 isn't in the interface declaration
> >for I2.
> >
> >Of course, the interface specification could include a set of the interfaces
> >in the specification and all of the interfaces that they extend.
> 
> Sorry; I meant to state the latter, but it got left out.
> 
> This brings me to another API-level question...
> 
> Is it necessary or desirable to have IInterfaceSpecifications represent 
> __iter__() differently from flattened()?
> 
> That is, given:
> 
> class I1(Interface): pass
> class I2(I1): pass
> 
> spec = InterfaceSpecification(I2)
> 
> is it necessary that:
> 
> list(spec) == [I2]
> 
> Or is it sufficient if:
> 
> I2 in list(spec)
> 
> That is, is it acceptable for an InterfaceSpecification to simply list its 
> contents in flattened form?
> 
> The current (outdated) spec on the Wiki says that __contains__ returns true 
> "if the given interface is one of the interfaces in the specification and 
> false otherwise".  This doesn't address extends().
> 
> My own inclination is that the most desired semantics of 
> IInterfaceSpecification are actually as follows:
> 
> class IInterfaceSpecification(Interface):
> 
>      def __iter__():
>         """Iterate over all IInterface objects that would be considered a 
> member of this spec
>            by __contains__()"""
> 
>      def __contains__(interface):
>         """Return true if 'interface' is a member of any specification
>            aggregated by this one, or is this specification.  'interface' must
>            implement IInterface."""
> 
> class IInterface(IInterfaceSpecfication):
>      ...
> 
> By implication, therefore, 'extends()' would not then be strictly necessary 
> in IInterface, since 'IFoo in IBar' would be true if IBar is or extends 
> IFoo.  (It might be useful to keep it around anyway.)
> 
> If an interface spec (declaration? set?) doesn't have to distinguish 
> between iter() and flattened(), its semantics are much simpler, and its 
> __iter__/__contains__ are now symmetrical.  Implementing mutable interface 
> specs is also cleaner, because they can simply loop over the things being 
> added to them, and add them to an internal dictionary.
> 
> This brings to light another point of unclear semantics in the current 
> spec, as I understand it.  The 'add()' and 'remove()' methods do not say 
> anything with respect to extends()-ness.  That is:
> 
> s1 = InterfaceSpecification(I2)
> s1.add(I1)  # is I1 added?  it is, after all "contained" by s1 already...
> s1.remove(I1)  # now what happens?
> 
> 
> _______________________________________________
> Zope3-dev mailing list
> Zope3-dev@zope.org
> http://mail.zope.org/mailman/listinfo/zope3-dev