The Artima Developer Community
Sponsored Link

Weblogs Forum
Interfaces or Abstract Base Classes?

42 replies on 3 pages. Most recent reply: Dec 16, 2005 4:16 PM by Ed Suominen

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 42 replies on 3 pages [ 1 2 3 | » ]
Guido van van Rossum

Posts: 359
Nickname: guido
Registered: Apr, 2003

Interfaces or Abstract Base Classes? (View in Weblogs)
Posted: Aug 5, 2005 12:18 PM
Reply to this message Reply
Summary
I found this in my drafts, dated Feb 6 2005. I 'll just push it out now unedited. Original summary: I thought it was clear that we should add interfaces to Python, but Phillip Eby reminded me that years ago I rejected them in favor of Abstract Base Classes (ABCs). Why? I don't remember! Which do you prefer?
Advertisement

ABCs vs. Interfaces

I can't for the life of me remember why I would prefer ABCs over interfaces! And even if I did remember, I believe I have changed my mind since then.

The only argument that comes to mind is that ABCs don't require more syntax. That's usually a strong argument in Python. But it seems that at least two of the largest 3rd party projects in Python (Zope and Twisted) have already decided that they can't live without interfaces, and have created their own implementation. From this I conclude that there's a real need.

But if they can do it themselves (albeit with some heavy-duty metaclass magic), doesn't that prove we don't have to add them to the language? Not at all. The mechanisms used are ideosyncratic, fragile, and cumbersome. For example, you have to use __xxx__ words to declare conformance to an interface. Plus, there's duplicate work and interoperability. IMO this is language infrastructure that should be provided by the language implementation.

Many followups to my blogs about adding optional type checking to Python (given the latest design I'm leaving off the word "static" :-) said that interfaces were more important than type checking. Personally, I think they're interconnected: interfaces make much more sense if you can also declare the argument types of the methods, and argument type declarations in Python are unthinkable without a way to spell duck types -- for which interfaces are an excellent approach. Phillip Eby's Monkey Typing proposal is an interface-free alternative, but I find it way too complex to be adopted as a standard Python mechanism.

A few more arguments against ABCs: they seem the antithesis of duck typing. Using ABCs for type declarations suggests that isinstance() is used for type checking, and even if reality is not quite that rigid, this suggestion would be leading people into the wrong direction.

ABCs also allow, nay, encourage, "partially abstract" classes -- classes that have some abstract methods and some concrete ones. Of course, such a class as a whole is still abstract, but the resulting mixture of implementation and interface complexifies the semantics.

It has been suggested, especially by Ping, that there is a need to specify some semantics in interfaces. A typical example involves a file, where various operations such as readline() and readlines(), can be implemented by default in terms of a more primitive operation -- in this case read(). Unfortunately, I believe that this approach is not very practical, since those default implementations are usually inefficient, and the choice of the "most primitive" operation is often dependent on the situation. I also suspect that outside some common standard types there aren't all that many uses for this pattern. But if you have to do this, a mix-in class for the "default" functionality separate from the interface would work just as well as combining the two.

Specifically because they are not classes, interfaces allow for clear, distinct semantics. (That is, the semantics of interface objects; I intend for interfaces to be neutral on the issue of the semantics of the objects they describe.) For example, (not that I necessarily propose this, but this is one way that we could decide to go), in a class claiming to implement a particular method declared in an interface, it could be flagged as an error if the actual implementation required more arguments than declared in the interface, or (assuming we can have type declarations in interfaces as well as in classes) if the argument types didn't match.

Python has a strong tradition that subclasses may redefine methods with a different signature, and making that an error goes against the grain of the language. But the explicit use of an interface changes things and there is seems appropriate that a class should not be allowed to violate an interface it claims to implement.

So, while I haven't decided that Python 3.0 will have interfaces (or type declarations), I'd like to go ahead and hypothesize about such a future, and look at some of the standard interfaces the language would provide for various common protocols like sequence, mapping and file.

The File Interface

Let's start with files, because they don't require genericity to fully specify the interface. Here's my first attempt. Note that I'm simplifying a few things; I'd like to drop the optional argument to readline() and readlines(), and I'm dropping the obsolete API xreadlines():

interface file:

    def readline() -> str:
        "Returns the next line; returns '' on EOF"

    def next() -> str:
        """Returns the next line; raises StopIteration on EOF.

        next() has one special property: due to internal buffering,
        mixing it with other operations is not guaranteed to work
        properly unless seek() is called first.

        """

    def __iter__() -> file:
        "Returns self"

    def read(n: int = -1) -> str:
        """Reads n bytes; if n < 0, reads until EOF.

        This blocks rather than returning a short read unless EOF is
        reached; however not all implementations honor this
        property.

        (Did you know the default argument was -1?)

        """

    def readlines() -> list[str]:
        "Returns a list containing the remaining lines"

    def seek(pos: int, how: int = 0) -> None:
        """Sets the position for the next read/write.

        The 'how' argument should be 0 for positioning relative to
        the start of the file, 1 for positioning relative to the
        current position, and 2 for positioning relative to the end
        of the file.

        """

    def tell() -> int:
        "Returns the current read/write position"

    def write(s: str) -> None:
        "Writes a string"

    def writelines(s: list[str]) -> None:
        """Writes a list of strings.

        Note: this does not add newlines; the strings in the list
        are supposed to end in a newline.

        """

    def truncate(size: int = ...) -> None:
        """Truncates the file to the given size.

        Default is the current position.

        """

    def flush() -> None:
        "Flushes buffered data to the operating system."

    def close():
        "Closes the file, rendering subsequent use invalid"

    def fileno() -> int:
        """Returns the underlying 'Unix file descriptor'.

        Not all file implementations may support this, and the
        semantics are not always the same.

        """

    def isatty() -> bool:
        "Returns whether this is an interactive device"

    # Attributes

    softspace: int # read-write attribute used by 'print'

    # The following are read-only and not always supported

    mode: str # mode given to open

    name: str # file name given to open

    encoding: str|None # file encoding

    closed: bool # whether the file is closed

    newlines: None|str|tuple(str) # observed newline convention

This brings up a number of interesting issues already:

  • The file interface does not include standard object methods and attributes such as __repr__() and __class__. But it does include __iter__() since this is not supported by all objects.

  • Moreover __iter__() is defined different than the "generic" definition of __iter__() would be: since we know that a file's __iter__ method returns the file itself, we know its type. This is in general the case for standard APIs that are explicitly part of a specific interface; we'll see this again for __getitem__ later.

  • The argument to writelines() and the return value from readlines() are lists of strings. I really want to be able to express that in the interface definition. Even in Pascal, which has such a nice simple type system, you can say this! I'm using list[str], following the notation I used in an earlier blog where I was brainstorming about generic types.

  • Rather than distinguishing between None and its type, for conciseness I'm using the singleton value as its own type. While type(None) is not None and never will be, in type expressions, None stands for type(None).

  • In a few places, a value may be either a string or None; or either an int or None. I'm using the notation str|None respectively int|None for this, which also debuted in an earlier blog.

  • The argument to truncate() has a dynamic default. I'm proposing the notation ... for this; I don't want to say -1 because passing int -1 doesn't have the same effect, unlike for read(). The semantics of this notation are that an implementation may choose its own default but that it must provide one.

  • There's the thorny issue of some APIs that aren't always defined. I'm not going to introduce a notation for this yet; rather, I'll just say it in a comment. The default type checking algorithm will accept partial implementations of an interface.

  • The file interface has a few attributes, one of which (softspace) is writable. This must be supported or else the print statement won't work righty when directed to such a file. For now I'm using the notation:

    name: type
    

    and indicating the read-write-ness in a comment. The notation is less than ideal because it doesn't allow to attach a doc string. I could use this:

    name: type "docstring"
    

    but I fear that Python's parser isn't smart enough to always know where the type expression ends and the docstring begins (since 'type' can be an expression, syntactically).

  • Note that softspace is conceptually a bool, but implemented as an int, and that's how it's declared here.

  • The return type of close() is problematic. Usually it is None, but for file objects returned by os.popen() is is an int. I've chosen to leave out the '-> None' notation on the close() method, leaving its return type unspecified. I could also have written '-> int|None'. Or we could have a rule that allows a method that is declared to return None to return a different type, perhaps after subclassing.

  • It would be lovely to be able to declare exceptions, even if we don't assign any semantics to this (Java checked exceptions have turned out to be a horrible thing in practice). But I'm leaving this to a future brainstorm.

  • What about argument names and keyword parameters? In the above example, I don't intend to allow keyword parameters on any of the interfaces. But what if an interface wants to define keyword parameters? What if you want to require certain parameters to be given as keyword parameters (and you still want to declare their types)? Maybe we need a notation to explicitly say that an argument can or must be a keyword parameter? Or maybe it would be sufficient to allow leaving out the parameter name if it is supposed to be always positional? Then the declaration of read() would become:

    def read(:int = -1) -> str: "reads some bytes [...]"
    

The Sequence Interface

Here's my attempt at defining a generic sequence interface. Note that I'm declaring this as a generic type, with 'T' being the type parameter. This despite my earlier promise not to bother with generic types. I think they are both useful and easy to implement, even if there are some thorny issues left: a dynamic check for list[int] is very expensive (it has to check every item in the list for int-ness) and any mutation of the list might change its type:

interface iterator[T]:

    def __iter__() -> iterator[T]: "returns self"

    def next() -> T: "returns the next item or raises StopIteration"

interface iterable[T]:

    """An iterable should preferably implement __iter__().

    __getattr__() is a fallback in case __iter__ is not defined.

    Note that an iterator is a perfect candidate for an iterable, by
    virtue of its __iter__() method.

    """

    def __iter__() -> iterator[T]: "returns an iterator"

    def __getitem__(i: int) -> T: "returns an item"

interface sequence[T]:

    @overloaded
    def __getitem__(i: int) -> T: "gets an item"

    @overloaded
    def __setitem__(i: int, x: T) -> None: "sets an item"

    @overloaded
    def __delitem__(i: int) -> None: "deletes an item"

    def __iter__() -> iterator[T]: "returns iterator"

    def __reversed__() -> iterator[T]: "returns reverse iterator"

    def __len__(): int: "returns number of items"

    def __contains__(x: T): bool: "returns whether x in self"

    def __getslice__(lo: int, hi: int) -> sequence[T]:
        "gets a slice"

    def __setslice__(lo: int, hi: int, xs: iterable[T]) -> None:
        "sets a slice"

    @overloaded
    def __getitem__(x: slice) -> sequence[T]:
        "gets an extended slice"

    @overloaded
    def __setitem(x: slice, xs: iterable[T]) -> None:
        "sets an extended slice"

    @overloaded
    def __delitem__(x: slice) -> None:
        "deletes an extended slice"

    def __add__(x: iterable[T]) -> sequence[T]:
        "concatenation (+)"

    def __radd__(x: iterable[T]) -> sequence[T]:
        "right-handed concatenation (+)"

    def __iadd__(x: iterable[T]) -> sequence[T]:
        "in-place concatenation (+=)"

    def __mul__(n: int) -> sequence[T]: "repetition (*)"

    def __rmul__(n: int) -> sequence[T]: "repetition (*)"

    def __imul__(n: int) -> sequence[T]: "in-place repetition (*=)"

    # The rest are all list methods -- should we really define these?

    def append(x: T) -> None: "appends an item"

    def insert(i: int, x: T) -> None: "inserts an item"

    def extend(xs: iterable[T]) -> None: "appends several items"

    def pop(i: int = -1) -> T: "removes and return an item"

    def remove(x: T) -> None:
        "removes an item by value; may raise ValueError"

    def index(x: T) -> int:
        "returns first index where item is found; may raise ValueError"

    def count(x: T) -> int: "returns number of occurrences"

    def reverse() -> None: "in-place reversal"

    # But not sort() -- that's really only a list method

Some additional issues with this:

  • The syntax for declaring a generic interface (interface X[T]) requires a bit of a leap of faith. But without parameterization we can say so much less about a sequence than what is common knowledge (and what a type inferencer should know) that I find it nearly useless to bother defining a sequence type without this notation. Possibly an implementation that ignores the type parameter T would be acceptable; use of T would be purely for the benefit of the human reader.
  • I had to introduce two auxiliary interfaces:
    • iterator, something with primarily a next() method
    • iterable: something with primarily an __iter__() method, although something implementing __getitem__() will also work. That makes its declaration a bit awkward (with both methods being optional but at least one being required).
  • I struggled a bit with the two possible signatures for __getitem__ and friends: it is normally called with an int argument, returning a single item, but the extended slice notation (e.g. seq[1:2:3]) calls it with an argument that is a slice object, and then it returns a sequence. Declaring the argument and return types as unions feels unsatisfactory because it throws away information. I decided to use the @overloaded decorator, which can be implemented using a small amount of namespace hacking.
  • Should we have separate interfaces for immutable and mutable sequences? For now I'd rather only have one; the notion that an implementation may leave out methods naturally allows for immutable sequences.
  • Should the sequence interface mention virtually everything that a list can do, or should it be minimal?
  • Even if the sequence interface is inclusive (containing most list methods), I'd like to leave sort() out of it; sort() is really unique to the list type, and even if some user type defines a sort() method, it's unlikely to have the same signature as list.sort() (especially after what we did to this signature in Python 2.4). Feel free to prove me wrong.
  • In current Python, the + operator on standard sequence types only accepts a right operand of the same type (list, tuple or str). But the += operator on a list accepts any iterable! I think + on any two sequences, or even a sequence and an iterable, in either order, should be allowed, and should return a new sequence. However, iterable + iterable should be left undefined; this is because iterator + iterator is not defined, and I think it should not be.


Kay Schluehr

Posts: 302
Nickname: schluehk
Registered: Jan, 2005

Re: Interfaces or Abstract Base Classes? Posted: Aug 5, 2005 1:49 PM
Reply to this message Reply
I stay sceptical about "optional static typing" ( or however you rename it ) and interfaces in Python because I'm not sure how this stuff fits with Pythons dynamicity? Static types are assurances about the types of the values created in a program that can be checked without executing the program. If a type system is not broken and if it is implemented appropriately type safety can be assured. I don't see anything of this happening to Python with your inventions. If you continue to allow adding and removing object attributes at runtime you can never be sure that an object conforms to an interface except you make a complete check whenever a method expects an object with a certain interface. In the end I'm confused about what is reliable meta-information about my program and what is not?

By the way I don't understand "duck-typing". It seems to be a funny way to talk about Leibniz identity of indiscernibles pronouncing the behavioural aspect of some object. But no method signature can answer the question how some thing behaves. An interface can at best guarantee method calls and attribute access ( but not even that in Python ). So what is meant by a type in duck-typing?

Kay

bug not

Posts: 41
Nickname: bugmenot
Registered: Jul, 2004

Re: Interfaces or Abstract Base Classes? Posted: Aug 5, 2005 2:37 PM
Reply to this message Reply
> # The following are read-only and not always supported

I don't think it's a good idea to include some attributes in an interface that are not always supported. This is exactly what I want to avoid when using an interface, I want a guarantee that all the interface requirements are met.

If there are some attributes that are OS dependant or will not be available on some file-like objects (like sockets), I think what attributes shouldn't be part of the Interface, or may to have 2 interfaces, like:


interface stream:
# ...
interface file(stream):
# ... (file specific attributes/methods)
[code]

Jonathan LaCour

Posts: 6
Nickname: jlacour
Registered: Dec, 2004

Re: Interfaces or Abstract Base Classes? Posted: Aug 5, 2005 3:52 PM
Reply to this message Reply
"The only argument that comes to mind is that ABCs don't require more syntax. That's usually a strong argument in Python. But it seems that at least two of the largest 3rd party projects in Python (Zope and Twisted) have already decided that they can't live without interfaces, and have created their own implementation. From this I conclude that there's a real need."

Just because they "can't live without interfaces" doesn't really mean that there is a real need. I think interfaces and static typing are entirely against the spirit and power of Python. If those people want to use interfaces, then let them get together and create a third-party package for interfaces that they both agree upon and leave it third party.

I agree with one of the above posters that interfaces just don't lend themselves to a dynamic language like Python. In the end, they provide little usefulness apart from documentation. If you really want to achieve the effect of interfaces, build in something better than docstrings and more like Javadoc that will allow the user to document their code and generate really great documentation, along with information about what methods expect as parameters, and what they return.

In the end, I much prefer thinking in terms of "file-like objects" rather than in terms of "implements IFile".

Benji York

Posts: 5
Nickname: benji
Registered: Aug, 2005

Re: Interfaces or Abstract Base Classes? Posted: Aug 6, 2005 8:47 AM
Reply to this message Reply
> If those people want to use interfaces,
> then let them get together and create a third-party
> package for interfaces that they both agree upon and leave
> it third party.

"They" have: both Zope and Twisted now use the zope.interface package (http://www.zope.org/Products/ZopeInterface)

> I agree with one of the above posters that interfaces just
> don't lend themselves to a dynamic language like Python.

I'll grant you that in the small, they might not provide much value, but when you start talking about adaptation, making security declarations about objects, or interfacing with large/complex libraries, interfaces make much more sense. Luckally we can have both, as interface checking will be optional.

damien morton

Posts: 15
Nickname: dmost
Registered: Jan, 2004

Re: Interfaces or Abstract Base Classes? Posted: Aug 6, 2005 10:15 PM
Reply to this message Reply
It is only recently in my career that I have started using languages that support interfaces. I went from mainly using Python to mainly using C# about 3 years ago.

I find interfaces in C# to be usefull, but they would be far more usefull if one could define default methods on the interface (which would have no access to instance state), and if the interface defention allowed pre/post-conditions to be specified as part of the contract.

Without pre/post-conditions being specified, an interface adds little value beyond matching the names of methods and the types of their arguments.

Elizabeth Wiethoff

Posts: 89
Nickname: ewiethoff
Registered: Mar, 2005

Re: Interfaces or Abstract Base Classes? Posted: Aug 6, 2005 11:13 PM
Reply to this message Reply
Interfaces. Ugh. Smells like Java. And why does Java have interfaces? Because it doesn't allow multiple inheritance. And why doesn't it allow multiple inheritance? The fear that the programmer will shoot his foot off with it. And why Java's dire need for inheritance/interface? Compile-time type checking.

Python doesn't have compile-time type checking and has already put a lot of thought into MRO and the diamond problem. Why not encourage multiple inheritance of ABCs?

Perhaps developers are accustomed to envisioning a Java-like implementation when envisioning large projects. The only true benefit I can see to interfaces (and static-like types) is how much easier it might be to create a powerful IDE for Python developers. Or perhaps, how much easier it might be to adapt an existing IDE to do cool things with Python code. The better the IDE, the easier the large project.

Joe the User

Posts: 1
Nickname: joetheuser
Registered: Aug, 2005

Re: Interfaces or Abstract Base Classes? Posted: Aug 7, 2005 7:12 AM
Reply to this message Reply
> def readline() -> str:

What the "str" here should be? Is it the type "str" or any object providing the "str" interface, defined somewhere else?

In the standard library there are many methods that require a "file-like" object (one example is ftplib). Defined as part of some interface, what will they require, a type "file" or an object of any type that provides the "file" interface?

With interfaces defined in terms of ABC, we have no such a problem - the interface is a class.

Gregg Wonderly

Posts: 317
Nickname: greggwon
Registered: Apr, 2003

Re: Interfaces or Abstract Base Classes? Posted: Aug 7, 2005 10:06 AM
Reply to this message Reply
> Interfaces. Ugh. Smells like Java. And why does Java have
> interfaces? Because it doesn't allow multiple inheritance.
> And why doesn't it allow multiple inheritance? The fear
> that the programmer will shoot his foot off with it. And
> why Java's dire need for inheritance/interface?
> Compile-time type checking.

While these points might be some of the motivation, there are many benefits to having interfaces. One of the primary benefits is in the use of RMI for remote access to services. Having an interface means that a small amount of code is shared by all to document how the systems work together. The implementation comes to the user via mobile code, and this, makes it possible to adapt and extend implementations independently of the interface definition.

J2EE and a lot of other containers encourage you to put everything in the JVM and utilize interfaces such as SQL, XML etc. to exchange information. Both SQL and XML are interfaces by definition. There is a specific template of syntax/semantics that you have to use to talk to the remote system.

It's not an interface that is part of the programming language syntax and type system (not yet anyway), but it is an interface.

So, interfaces have been proven to be very important to separating implementation from contract/description. Java's interfaces empower the developer to do a lot of things with more visible documentation of the specifics of the system.

Poorly defined interfaces are those that are so generic that you can't possibly guess what might happen. Better defined interfaces have narrow enough argument lists that it is clear what will happen just by eyeballing the javadocs.

Clearly a wide range of good vs bad interface design has occcured in lots of places. Proper architectures come from experience and training, not from language features. Language features enable the developer/architect/programmer to be more effective at expressing and designing the structure of the software that is the architecture!

Jonathan LaCour

Posts: 6
Nickname: jlacour
Registered: Dec, 2004

Re: Interfaces or Abstract Base Classes? Posted: Aug 7, 2005 6:35 PM
Reply to this message Reply
> ... there
> are many benefits to having interfaces. One of the
> primary benefits is in the use of RMI for remote access to
> services. Having an interface means that a small amount
> of code is shared by all to document how the systems work
> together. The implementation comes to the user via mobile
> code, and this, makes it possible to adapt and extend
> implementations independently of the interface
> definition.

So, you are saying that beyond documentation, interfaces are good for "documenting how the systems work together"? Wow, way to take an entire paragraph to restate and prove my point! Interfaces are good for very few things:

1. Documenting how things work. This can be achieved just as well without the use of interfaces.
2. Static type checking. This is just about as far from Pythonic as I can think of, and can already be done via metaclasses, decorators, and any number of other methods. In addition, type checking is automatically slower than not type checking, since it will have to occur at runtime.
3. "Adaptation" systems, but this is just one way to do it. Technically, you don't need an interface at all for adaptation, just a string that describes that interface. I have written systems like this before, and its silly to state that interfaces are the _only_ way to do it.

The only other argument I have heard is that they are useful in "large systems" but aren't necessary in "small systems" as someone said above. I don't buy this argument either, as I have been writing large systems in Python for a long long time, and I have never needed interfaces, just good documentation.

> J2EE and a lot of other containers encourage you to put
> everything in the JVM and utilize interfaces such as SQL,
> XML etc. to exchange information. Both SQL and XML are
> interfaces by definition. There is a specific template of
> syntax/semantics that you have to use to talk to the
> remote system.
>
> It's not an interface that is part of the programming
> language syntax and type system (not yet anyway), but it
> is an interface.

Your point is that SQL and XML are in some way interfaces of some kind. Sure, they are. But your point brings to mind an excellent example of the differences between the Pythonic "protocols" way of doing things versus the Java/C# "interfaces" way of doing things: two very popular ways to write web services (REST and SOAP).

SOAP is created by Java/C#/XML/strongly-typed people and has giant WSDL descriptor files to state how services work, XML schemas to type and define each and every interaction, and tons of validation, type checking, and static definition for things. REST takes a different approach, relying more on the developer to write good documentation. SOAP is popular amongst C#/Java people, but is really looked down upon by dynamic language people (Python, Ruby, etc) because its overly complex. REST is easier to implement, works better, and is inherently faster!

To me, adding interfaces to Python would go against everything that Python is about. Come up with something else to do the same thing in a more Pythonic way, and maybe I could be convinced. Right now its just complexity for the sake of complexity. If you really feel some need in your heart for interfaces in your language, then you also want static typing, and you should just use Java or C#. You would feel more comfortable there.

> So, interfaces have been proven to be very important to
> separating implementation from contract/description.
> Java's interfaces empower the developer to do a lot of
> f things with more visible documentation of the specifics
> of the system.

I have worked with very large Java systems that have been created upon Interfaces as the core method of integrating with frameworks, and I always found it to be overly complicated and difficult to use. Java libraries often work this way, and using them often requires me to implement a bunch of interfaces that I may not even like the design of. In python, libraries usually have a few simple module-level methods or a few useful classes that allow me to get things done without having to go out of my way to reimplement my classes, or inherit anything.

> Poorly defined interfaces are those that are so generic
> that you can't possibly guess what might happen. Better
> defined interfaces have narrow enough argument lists that
> it is clear what will happen just by eyeballing the
> javadocs.

Most interfaces are poorly defined. Adding this to the language would introduce a ton of poorly defined interfaces to the Python world, and I don't think thats something I am really excited about.

> Clearly a wide range of good vs bad interface design has
> occcured in lots of places. Proper architectures come
> from experience and training, not from language features.
> Language features enable the
> e developer/architect/programmer to be more effective at
> expressing and designing the structure of the software
> that is the architecture!

But people who seem to want interfaces in Python (2 projects out of the entire Python world... *TWO*) have implemented one that they can live with. Thats great, let them use their own modules for doing this thing that they think is important. But don't put it in the language.

Christopher Diggins

Posts: 1215
Nickname: cdiggins
Registered: Feb, 2004

Re: Interfaces or Abstract Base Classes? Posted: Aug 7, 2005 11:12 PM
Reply to this message Reply
> I find interfaces in C# to be usefull, but they would be
> far more usefull if one could define default methods on
> the interface (which would have no access to instance
> state), and if the interface defention allowed
> pre/post-conditions to be specified as part of the
> contract.

Add to that that you don't have to explicitly specify that an interface is implemented and you have a Heron "concept". See: http://www.artima.com/weblogs/viewpost.jsp?thread=121827 .

I think that including preconditions, postconditions, concrete methods, and structural subtyping (implicit interface implementation) are all interesting ideas for any language including Python.

Maarten Hazewinkel

Posts: 32
Nickname: terkans
Registered: Jan, 2005

Tests as Interfaces Posted: Aug 8, 2005 6:08 AM
Reply to this message Reply
I agree with the people who are sceptical about whether the whole interfaces concept fits with the dynamic spirit of Python.

Interfaces intend to nail down a set of method signatures that apply to objects of classes implementing those interfaces. However, I think there are already easy and powerful ways of asserting this, and more.

A unit test can define not just the signature, but also semantics of objects. This can include any condition expressable in Python, including things like pre-/post- conditions and invariants. As I see it, this provides all the power of interfaces, without needing any additional language magic.

Jonathan Ellis

Posts: 7
Nickname: jbellis
Registered: Aug, 2005

Re: Interfaces or Abstract Base Classes? Posted: Aug 8, 2005 9:04 AM
Reply to this message Reply
Why is this worth breaking Duck Typing?

Zope and Twisted are the two most un-pythonic high-profile projects that happen to be written in python that I can think of. "Zope and Twisted (think they) need it" is a lousy reason to add a feature that will be horribly mis-used by the Java don't-get-zen-of-python-yet newcomers for years to come, particularly when said projects already have their own solution.

Calvin Mathew Spealman

Posts: 13
Nickname: ironfroggy
Registered: Aug, 2005

Re: Interfaces or Abstract Base Classes? Posted: Aug 8, 2005 11:44 AM
Reply to this message Reply
I have a lot of strong feelings about this issue, so I don't want to see the whole thing go sour in the face of people who keep misunderstanding the basic concepts. Guido, you never should have called this static typing in any way! People would have still gotten the ideas confused, but not nearly so many.

To Everyone who thinks Interfaces must mean Static Typing:
This is simply false. Interfaces in Python are more of an adaptation (pun!) of the interfaces in other languages, like Java and Obj-C, than the original ideas themselves. Python's duck typing is about as dynamic a typing system as you can get. So much so that it is really more of a lack of a typing system than anything else.

A lot of people are commenting, both here and elsewhere, that interfaces are little more than documentation. Perhaps, but if this is true, then you must look at the form of the documentation: it is machine readable, unlike human language. It is documentation to the runtime (they are dynamic, not static) that allows a more reliable way to identify what an object is capable of. Most importantly is the adaptation this allows, as the adaptation registry needs to know what all the objects can do, to make them do what you want them to do.

Now, on to my comments about Guido's post itself.

I really dislike the list[str] expression, because it leaves a gap when dealing with user-defined interfaces and types? If I have a type defined that is some container, and I then do foo[bar], how will Python know if I mean "foo with elements conforming to bar" or "the interface found in mapping foo by key bar"? This ambiguity is not a good idea. I propose instead that types must be valid expressions as in any other part of a Python script, with no special meanings. We can do things like listOf(str) to create an interface that is the list interface, but where all elements are of the str type. There is also some confusion on my end as to why you did list[str] and tuple(str). Was that a mistake? Finally, on this topic, I note that the | operator on types here is also breaking of normal expression semantics, and either the pipe operator used on types should return something as the listOf placeholder interface I mentioned, but matching any one of a choice of interfaces, or a callable be defined to pass a list of types to, also to gain such an object.

I'm also disliking the sequence[T] syntax. At least as it stands, it is too strange. I understand the meaning and reasoning behind it, but I propose another route. Why not get rid of the T stuff there, and instead define a second interface, which would inherit sequence. Call it typedsequence. This would define a new attribute elemtype, and define in the right places that certain arguments and return values must conform to elemtype. Now, how we refer to the attribute on an instance conforming to the element, from within the interface definition, I am not sure. There is no self argument to refer to, so perhaps this issues requires further thought.

Now, you define two extra interfaces here for the sequence, but I think you aren't taking it far enough. We need more fine-grained interfaces. We need to be able to say "this object contains other objects, and keeps them in an ordered sequence", while omitting a specification the elements are all unique (sets), or that they are referred to by unique keys (dictionaries). We can break these behaviors down to their most basic ideals, and mix and match to get the exact behavior we need, no less and hopefully no more, but more is OK if that's whats available. But the basic thought here is to be able to specific better the exact minimum that you want supported by the object.

And, one last note, in reguards to the "iterator + iterator" business. What if it were defined as returning an iterator, which would iterator just like the left iterator until StopIteration, and then use the right iterator. The implementation should handle both iterators and iterables.

Gregg Wonderly

Posts: 317
Nickname: greggwon
Registered: Apr, 2003

Re: Interfaces or Abstract Base Classes? Posted: Aug 8, 2005 12:17 PM
Reply to this message Reply
> > ... there
> > are many benefits to having interfaces. One of the
> > primary benefits is in the use of RMI for remote access
> to
> > services. Having an interface means that a small
> amount
> > of code is shared by all to document how the systems
> work
> > together. The implementation comes to the user via
> mobile
> > code, and this, makes it possible to adapt and extend
> > implementations independently of the interface
> > definition.
>
> So, you are saying that beyond documentation, interfaces
> are good for "documenting how the systems work together"?
> Wow, way to take an entire paragraph to restate and prove
> e my point! Interfaces are good for very few things:

Yes, but it is machine readable documentation that is a nice formal contract that can be verified absolutely.

Runtime typing and duck typing are flexible. But, they can also lead to a lot of extra work in test development, to do things that a static typing compiler already provides the ability to do. The static typing compiler gets written once so everyone can use its built in testing facilities.

An interface is a compile time test!

Flat View: This topic has 42 replies on 3 pages [ 1  2  3 | » ]
Topic: What C++ Does Wrong Previous Topic   Next Topic Topic: Vlists, Stacks and Hash-Tables


Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2014 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us