does lack of type declarations make Python unsafe?

Alex Martelli aleax at aleax.it
Wed Jun 18 11:01:28 EDT 2003


David Abrahams wrote:

> Alex Martelli <aleax at aleax.it> writes:
> 
>> But this has little to do with the need of 'type declarations'.  I
>> suspect that a statically typed language would also be better off
>> without them, relying on type inferencing instead, a la Haskell (and
>> Haskell's typeclasses to keep the inferencing as wide as feasible),
>> for example.  But I have no research to back this up;-).
> 
> I don't have any first-hand experience, but the experience of friends
> of mine who have used Haskell is that it can be exceedingly difficult
> to locate the source of a type error when it does occur, since the
> inference engine may propagate the "wrong" type back much further than
> the source of the error.

Surely the compiler should easily be able to annotate the sources with
the information it has inferred, including, in particular, type information.
Thus it cannot possibly be any harder to identify the error point than
if the same type declarations had been laboriously, redundantly written
out by hand -- except, at worst, for a slight omission in the tool of a
feature which would be easily provided.


> Furthermore, if you do everything by inference you lose the
> explanatory power of type declarations.

I think I know where you're coming from, having quite a past as a
static-type-checking enthusiast myself, but I think you overrate the
"explanatory power of type declarations".

What I want to be able to do in my sources is assert a set of facts
about "and at this point I know X holds".  Sometimes X might perhaps
be of the form "a is of type B", but that's really a very rare and
specific case.  Much more often it will be "container c is non-empty",
"sequence d is sorted", "either x<y or pred(a[z]) for some x>=z>=y",
and so on, and so forth.  Type declarations would have extraordinary
"explanatory power" if and only if "a is of type B" was extraordinarily
more important than the other kinds of assertions, and it just isn't --
even though, by squinting just right, you may end up seeing it that
way by a sort of "Stockholm Syndrome" applied to the constraints your
compiler forces upon you.

Types are about implementation, and one should "program to an interface,
not to an implementation" -- therefore, "a is of type B" is rarely what
one SHOULD be focusing on.  Of course, some languages blur the important
distinction between a type and a typeclass (or, a class and an interface,
in Java terms -- C++ just doesn't distinguish them by different concepts,
so, if you think in C++, _seeing_ the crucial distinction may be hard;-).

"e provides such-and-such an interface" IS more often interesting, but,
except in Eiffel, the language-supplied concept of "interface" is too
weak for the interest to be sustained -- it's little more than the sheer
"signature" that you can generally infer easily.  E.g.:

my procedure receiving argument x

    assert "x satisfies an interface that provides a method Foo which
            is callable without arguments"

    x.Foo()

the ``assert'' (which might just as well be spelled "x satisfies
interface Fooable", or, in languages unable to distinguish "being
of a type" from "satisfying an interface", "x points to a Fooable")
is ridiculously redundant, the worse sort of boilerplate.  Many,
_many_ type declarations are just like that, particularly if one
follows a nice programming style of many short functions/methods.
At least in C++ you may often express the equivalent of

"just call x.Foo()!"

as

template <type T>
void myprocedure(T& x)
{
    x.Foo();
}

where you're basically having to spend a substantial amount of
"semantics-free boilerplate" to tell the compiler and the reader
"x is of some type T" (surprise, surprise; I'm sure this has huge
explanatory power, doesn't it -- otherwise the assumption would
have been that x was of no type at all...?) while letting them
both shrewdly infer that type T, whatever it might be, had better
provide a method Foo that is callable without arguments (e.g. just
the same as the Python case, natch).

You do get the "error diagnostics 2 seconds earlier" (while compiling
in preparation to running unit-tests, rather than while actually
running the unit-tests) if and when you somewhere erroneously call
myprocedure with an argument that *doesn't* provide the method Foo
with the required signature.  But, how can it surprise you if Robert
Martin claims (and you've quoted me quoting him as if I was the
original source of the assertion, in earlier posts) that this just
isn't an issue...?  If the compilation takes 3 seconds, then getting
the error diagnostics 2 seconds earlier is still a loss of time, not
a gain, compared to just running the tests w/o any compilation;-)...


I do, at some level, want a language where I CAN (*not* MUST) make
assertions about what I know to be true at certain points:
1. to help the reader in a way that won't go out of date (the assert
   statement does that pretty well in most cases)
2. to get the compiler to to extra checks & debugging for me (ditto)
3. to let the compiler in optimizing mode deduce/infer whatever it
   wants from the assertions and optimize accordingly (and assert is
   no use here, at least as currently present in C, C++, Python)
But even if and when I get such a language I strongly doubt most of
my assertions will be similar to "type declarations" anyway...


Alex





More information about the Python-list mailing list