[Types-sig] Scarecrow Proposal

Jim Fulton jim@Digicool.com
Tue, 24 Nov 1998 13:03:09 +0000

M.-A. Lemburg wrote:
> To be honest: I just flew over it at the time and then decided it
> was a good thing but not something that would interest me too much.
> After a while I started to see that this could be the solution to
> providing "static" typing in a very smart way (with interfaces being
> used as "type" tags providing all kinds of nifty details to possible
> optimizing engines

Perhaps someone will prove me wrong, but I expect that optimization
engines would want certain implementation information that would
be absent from a purely behavioral specification.

Hm.  Maybe it would be worth consider additional meta objects
(other than interfaces) that could be attributed to classes
or objects to give optimization hints.

> -- which is a great advantage over just defining
> X to be an integer: the optimizer could query the type to find out
> the best and most suitable way to produce code for it; it might even
> be able to decide which algorithm to pick depending one the features).
> That got me interested again and so here I am ;-)
> The above question is not so much about strategy, it is about
> ease of implementation: interfaces could benefit from inheritance
> too.

With the Scarecrow proposal, interfaces get to use inheritence too.

> Since interfaces and classes belong to two worlds this would
> have the great benefit of reuse for interfaces too (e.g. to specify
> the Sequence protocol in all kinds of different flavors).
> > > Is this just to make sure you can't mix classes and interfaces
> > > in __bases__ ?
> >
> > No, it is to:
> >
> >   - Reinforce the separation between implementation and
> >     interface, and
> >
> >   - To avoid requiring that subclasses must implement
> >     all the interfaces of base classes.
> This is another thing I didn't understand in your proposal:
> why do interfaces have to actually define method signatures
> at all ?

They don't, but most people want signatures to be included in interface

> Since interfaces will be used as tags only this would
> confuse the hell out of newbies when they find that they can't
> call those methods.

If an interface provides a method signature, then an object that
implements the interface is contractually bound to provide it too, 
so newbies and anyone else should feel free to call the object.

Note that signatures will *not* be available as attributes of
the interface.  For example:

  class FooInterface(Interface):
     def spam(a, b): 
        "blah blah blah :)"

  FooInterface.spam # raises an attribute error 
> IMHO, interfaces ought to have information query methods, not
> "real" ones that are only given to describe which methods are
> expected to be implemented by a class conforming to an interface.

I agree.

> I would put more emphasis on the tagging nature of interfaces
> rather than making them look like a C++ base class.

I couldn't agree more.
> The methods signature of the interface could well be stored
> using other means, e.g. by using a class defined only for this
> purpose:
> # Create a Sequence interface singleton
> class Sequence(Interface):
>         # Class defining the signatures of the methods that
>         # a Sequence conforming class must define
>         class signature:
>                 def __getitem__(self,i):
>                         """ Get item number i from the sequence
>                         """
>         def check(self,Class):
>                 """ Check whether Class actually conforms
>                     to the signatures defined above.
>                 """
>         # Flags for the optimizer
>         getitem_indices_are_integers = 1

This isn't necessary, since Interfaces won't be classes.
> Sequence = Sequence()

This won't be necessary either.  

  class FooInterface(Interface): ...

creates an *interface*, not an interface class.

I'll post me initial implementation later today.
This should make things a little bit clearer.

> # A class stating conformance to the Sequence interface:
> class MyList(UserList):
>         __interface__ = (Sequence,)
> > > IMHO, we should use as much as possible from the
> > > existing features, so I think building the interface hierarchy
> > > with plain Python classes
> >
> > Why do you care that plain Python classes are used.
> Makes things simpler. Classes already provide most of the
> functionality needed, IMHO, and so why not simply reuse them ?!

Actually, they get in the way.  Using separate objects is
really much simpler, as I think you'll see when I post me code. :)
> > > and then sticking them into the class
> > > hierarchy as __implements__ (should probably be named __interfaces__;
> > > a builtin function implements() could take care of the actual
> > > lookup in whatever is suitable).
> >
> > Yes.
> >
> > > If there are strong reasons for making the two different in the
> > > sense that type(class) is not type(interface), then I'd opt for
> > > simply cloning the class implementation by creating a second
> > > type object that is simply a copy of the class' one.
> >
> > This is not necessary.  It's easy to use the meta-class hook
> > to have class statements create Interface instances that are
> > not classes.
> Ok. But why not use singletons as the one above ?

The meta-class hook is simpler. 8-o  I was surprized 
> > >  Would this proposal get us closer to static typing ?
> >
> > If we ever do static typing, then I would hope that the
> > static typing would use interfaces.  Other than that, I don't know.
> >
> > > I'm thinking of a way to declare a named object ABC as having
> > > an interface XYZ (e.g. a function could be assigned an interface
> > > stating that the first argument must be an integer).
> > >
> > > Since the interface hierarchy is something that is built dynamically,
> > > the compiler would have to be given two things: an already executable
> > > script INT that builds the interface hierarchy and the source script SRC
> > > referring to this hierarchy. It could then optimize e.g. the function
> > > calls
> > > to abc knowing that the first argument is an integer and also add
> > > checks at C level to ensure this (a PyInt_Check() is a whole lot
> > > faster than the same check via type() in Python).
> >
> > I really don't think that the interface mechanism that I propose
> > is going to be very useful for optimization.  For example, knowing
> > that an object conforms to some "integer" interface should not tell you
> > that it has a particular implementation, so, for example, you can't assume
> > that it's of type PyInt_Type.
> But I could define an Integer interface to mean: objects conforming
> to this interface will work fine with the builtin int() and the
> optimizer may convert them using int() to enable better ways of
> storing their values. (The object could also define a reverse
> method, e.g. reinit_from_int() to reverse that trick -- all well
> definable in an interface definition.)

Fair enough.  The interface should probably say, if it can, what the 
possible range of values is.  (e.g. can a 16-bit integer be used at the
C level, must a python long be used, etc.)

Jim Fulton           mailto:jim@digicool.com
Technical Director   (540) 371-6909              Python Powered!
Digital Creations    http://www.digicool.com     http://www.python.org

Under US Code Title 47, Sec.227(b)(1)(C), Sec.227(a)(2)(B) This email
address may not be added to any commercial mail list with out my
permission.  Violation of my privacy with advertising or SPAM will
result in a suit for a MINIMUM of $500 damages/incident, $1500 for