Python 1.6 The balanced language

Alex Martelli aleaxit at yahoo.com
Wed Sep 6 04:58:35 EDT 2000


"Suchandra Thapa" <ssthapa at harper.uchicago.edu> wrote in message
news:slrn8rb7aa.92u.ssthapa at hepcat.uchicago.edu...
> Manuel Gutierrez Algaba <thor at localhost.localdomain> wrote:
> >On Tue, 5 Sep  Alex Martelli <aleaxit at yahoo.com> wrote:
> >>
> >>You do have the notion of typeclasses in Python: "a sequence",
> >>for example, or "a file-like object"; you just lack the way to
> >>*EXPRESS* this notion simply, directly, and explicitly _in the
> >>language itself_.  So you express it in docs & comments, but
> >>those are often not as precise as one would wish (and as an
> >>expression in a formal language might make things): when
> >>somebody says 'you pass a file-like object', what methods are
> >>going to be called on it -- write? read? writelines? readlines?
> >>close?  _Good_ docs would say that -- but why not have a
> >>way to say it in the language itself?
> >
> >No, an object that implements those methods required to be
> >considered a sequence is not a type(object )= sequence
> >
> >Fortunately,  the notion of objects that accomplish certain
> >behaviours is far more general and flexible than types.
>
>     I think Alex was trying to make the point that the notion
> of a type class captures the idea of specifying that a certain
> object needs to have certain properties.  For example, in

Of course -- it's ONE of the thing it does.  Further (a point
I had not mentioned in the above quote), a typeclass offers one
of the best and most elegant way to do 'mixin' kinds of jobs:
help the programmer when N methods may be defined in terms of
each other.  The technique is well-known, and well worth
knowing since it also applies to Python, so, here's an example:

In Python, you could do this (relying on inheritance of
implementation, and overriding, exclusively):

class WritableFileMixin:
    def write(self, stuff):
        self.writelines((stuff,))
    def writelines(self, stuff):
        for stiff in stuff:
            self.write(stiff)

These two mutually recursive methods do not appear very
useful, do they?-)  But, they *are*!  The usage
convention is that a user class, that wants to implement
a writable-file-like-object, inherits from the mixin and
overrides EITHER of the two methods; automatically, then,
the other method will be defined in terms of the overridden
one. It's of course OK to override both, but then it's the
programmer's concern to ensure the semantic consistency is
kept; this might be useful basically for efficiency in
some cases (avoiding an unneeded indirectness).

Deriving this while overriding neither method is a violation
of protocol that will lead to a serious runtime error (a
stack-overflow due to unbounded mutual recursion) if either
method is ever called.  Pity there is no way to express this
protocol in the Python language: it must be left to docs
and/or comments *exclusively* (hmmm, I wonder if a metaclass
or extensionclass might in fact be used to optionally check
the protocol -- it would still be at runtime, of course, but,
at least, the usage error would be diagnosed much earlier and
in a possibly more direct/usable way; this bears thinking...).

Anyway, a typeclass would directly both express 'the type
implements these methods', AND offer implementation help
when 'deriving' a type from the typeclass.


> Haskell type classes are used to specify what types can be tested
> for equality and to define how to test these types for
> equality (through the use of an instance declaration).

I think you're one metalevel off here -- it's not that
_types_ can be tested for equality, but rather _two
objects both belonging to a type_ (which instances Eq) can
be so tested.  It's unfortunately easy to verbally slip
between metalevels when discussing this (I'm sure I've
committed several such errors myself in these discussions).


> >>Now THIS is 'wasting the possibilities some functions
> >>may provide' -- because the language is not expressive
> >>enough to supply a notation for the typesystem it is
> >>in fact using...
> >
> >Ok, in python apart from ints and char , we don't use types,
> >not at all, we don't need them and they're ugly. If we really
> >need to do some checkings we can check the properties of the
> >object, that is much flexible and exhaustive than type.
>
>     But typeclasses capture the notion of needing certain
> properties for given types.  With static type checking, you
> gain something over a runtime check since you don't need to
> keep type information and don't need to deal with runtime errors.

Well, you still do need to deal with SOME 'runtime errors', aka
(synchronous) 'exceptions', but if the compiler can do some of
that work for you earlier, it does lessen your runtime burden
a bit, yes.  However, in a Python context I don't see the
runtime-efficiency as being the paramount consideration; rather,
"expressive power" seems to me to be more important and Pythonic.

Explicit is better than implicit -- one of the Python mantras.

Being able to say *in the language* "and this here argument will
need to implement these here methods" would let the programmer
make explicit what currently must be left implicit -- I would
see it as _more Pythonic_, even if only modest code-generation
benefits ensued (Python is so nicely fluid & dynamic -- features
we *DON'T* want to lose! -- that compile-time ensuring things
is in general a very hard problem; so the compiler would have
to insert the runtime-checks -- still a bit better than having
to do them by hand, mind you:-).  Something akin to a typeclass
would be a pretty nice, usable way to let these kind of things
be explicitly expressed.

> Even with your concept of just checking for properties, you still
> need to insert code into the compiled version that deals with the case
> where you don't have the proper method.

Yes, and in practice full checking may well turn out to be too
hard -- it's not enough that 'foo' has a 'write' method, that
method must be callable with exactly one argument, for example.
In practice, a try/except around the foo.write(whatever) call
may be better (assuming you have any idea of what to do when
the call attempt fails in various ways -- a non-Pythonic but
practical mantra is "don't check for errors that you don't
know what to do about":-).


> >>Having a *good* typesystem need be nothing as confining as
> >>that; you don't seem to have much experience using such
> >>typesystems -- I strongly suggest you try out a few before
> >>expressing such trenchant judgments.
> >>
> >
> >I have programmed in C for countless years, a bit in C++ and
> >a bit in Java. And in Pascal .  And yes, I won't like types, ever.
> >
> >The two brightest languages that come to my mind ( LISP, python)
> >don't use types.
>
>     C/C++, Java and Pascal don't really have good type systems.

Agreed (and neither does Eiffel IMHO -- too much burden being
placed on the single idea of 'class', no type-inference, &c).

> The compiler can't figure out types without explicit declarations.
> With a good type system, your compiler can use type inference to
> figure out what types to expect and just needs explicit type declarations
> at a few places as hints. For example in Haskell code like,
>
> data Color = Red | Green | Blue
>              deriving Eq
>
> permute x | x == Red   = Green
>   | x == Green = Blue
>   | x == Blue  = Red
>
> asking for the type of permute returns permute :: Color -> Color. The
compiler
> is smart enough to figure out that x needs to belong to the color type and
> that permute returns a color.  This is in contrast to C/C++ where you
would
> need to define permute with explicit type declarations.  If you compare
this
> to the equivalent python or lisp code, they are remarkably similar.

Plus, in Haskell you *MAY* add an explicit assertion about permute's type
IF YOU WANT: it's up to you, as a programmer, to decide whether here it
is worth being explicit (for clarity, to help future readers of your
code understand what's going on, for example) or whether it's better to
just let type-inference work by itself.


Alex






More information about the Python-list mailing list