Who's minister of propaganda this week?

Alex Martelli aleaxit at yahoo.com
Sun Mar 18 15:55:59 EST 2001


"Michael Chermside" <mcherm_python at yahoo.com> wrote in message
news:mailman.984937946.5318.python-list at python.org...
    [snip]
> First of all, I completely agree that telling whether an object has
> the right method names and signatures (an "interface" in the java
> sense) is only a very limited subset of defining the signatures,
> pre-requisites, post-conditions, and invariants. Eiffel allows
> something like this... let's call the idea a "contract". I
> think it would GREAT if we could specify our strict typing in terms
> of "contracts" instead of the more limited "interfaces".

I would frame it in a slightly different way: that each interface
ideally needs to be 'completed' by including the contracts on
its methods (and abstract-state invariants).

> Compilers could NOT be expected to verify at compiletime that the
> pre-requisites were being satisfied, but they could at LEAST
> verify that the object being used claimed to implement that
> contract.

"Explicit is better than implicit" supports this.  Right now, in
Python, we only have _implicit_ interfaces -- and we pay some
price for that (for example, when we mention a 'sequence
interface', it's often not 100% clear if we only need suitable
behavior of the __getitem__ method, or also a __length__,
etc, etc).

However, the language constraints needed to make even this
'assertion to implement' verifiable *at compile time* are still
too strong for what little further advantage you gain.  The
documentation advantages of contract-ish interfaces are not
dependent on their compile-time vs run-time behavior, and
decent unit-tests will ensure the run-time checks are in fact
exercised (with clearer diagnostics than currently one can get
from typical contract-violation errors).

The extra advantage in terms of programmer productivity of
getting the diagnostics earlier may be, say, 5% or so -- with
a cost on the same scale of, say, 10% or so, for the extra
constraints of static typing.  Which is where we come in:-).

In other words: the undoubted advantages of interfaces with
programming-by-contract annotations do not really militate
in favour of statically typed languages vs dynamically typed
ones.


> On the occasions when I want to write something which works on
> all objects of a certain behavior, I define an interface for
> the behavior (even in languages which don't have direct support
> for "interface") and specify that all appropriate objects
> implement the interface. In fact, I often write multi-paragraph
> comments on how the interface should behave, so that it's really
> more of a "contract" than an interface. When I'm being good,
> (and I'm good much more often lately) I even write unit tests to
> enforce it.

Excellent (and static typing does not really help you check
your comments:-).  But, in large-scale software development,
you do not fully control this; there will be existing components,
that might well work just fine with other components... except
that, being developed separately and independently (and/or
not tolerating mutual dependencies) will not be inheriting from
each other's interfaces.  I'm not saying this _can't be solved_ --
I _am_ saying that solves it takes work _and_ complication
(templates, multiple inheritance, delegation, wrapping) and a
10% productivity impact is a _conservative_ evaluation of it.

Further -- your 'design space' itself (within a component, or
between components you control) gets constrained by the
language and object-model limitations coming from the static
typing characteristics thereof.  You may well be even considering
only about half of the architectures -- and there is a chance
that the optimal architecture may be among those that static
typing doesn't even let you _think_ of.

For example, say that you want to organize certain objects
in a container/contained hierarchy, with no nesting limits.

All existing objects will be leaves in the resulting tree.  Why
does this imply that such existing objects need to inherit
from a certain interface asserting "I may or may not be a
container" (perhaps with a default implementation stating
"I am _not_ a container after all")?  This is invasive, and
forces a logically uneeded dependency on the existing objects;
they shouldn't have to know about these organizing
superstructures at all!  In a dynamically typed language,
you will define an interface (and perhaps a default
implementation thereof) *only for container objects*, i.e.,
the "new" organizing superstructure.  Each container will
hold a set (e.g. a list, or dict) of (suitably tagged) references
to other objects; for recursive walks on the tree, one will
dynamically test whether a given object is-a container (else,
it's a leaf).  It's as simple as this; no headaches.  Any
headaches that DO come with this useful pattern are all
costs of using it with stating typing...!-)

If one ever considered only "green-field" development,
where no "existing objects" may possibly exist, maybe
the costs would be lower (there would still be some, as
the might-want-to-be-contained objects would still
have to multiply inherit the appropriate interface for
the _sole_ purpose of satisfying the static checks, a
pure overhead cost in terms of complication).  But this
is not a realistic hypothesis anyway -- standard and
other useful libraries have just too much useful stuff
to make it sensible to eschew them for the sake of
design purity:-).


> ... I'm just learning this stuff. In fact, I have been working
> with dynamically typed languages only for a very short time. So
> my own take-away is that I should really try to exercise the
> ability to make more extravagant use of polymorphism when working
> in dynamically typed languages, because I may discover (if my
> experience is similar to yours) that I'm saving 10% of my time,
> by avoiding awkward contortions that I don't even realize I'm
> doing now.

Good point.  I may keep talking for ages, but nothing I say will
substitute for actually getting some hands-on experience!-)


Alex






More information about the Python-list mailing list