[Types-sig] Sample declarations

Paul Prescod paulp@ActiveState.com
Tue, 13 Mar 2001 09:18:12 -0800


Guido van Rossum wrote:
> 
>...
> 
> I think you're on a slippery slope with some assumptions about numeric
> types here:
> 
> - Your test for number assumes that something can be converted to
>   complex.  That may not be true.

What's an appropriate definition for number? operator.isNumberType()?

> - Your test for Integer includes float/complex numbers with integral
>   values; that doesn't work, e.g. a[1.0] raises TypeError if a is a
>   sequence.

And yet this works:

open("c:\\autoexec.bat", "r", 5.0).read()

Is it by design that these two things work differently? Or is it an
implementation quirk? 

And if it is an implementation quirk then maybe we should use this as an
opportunity to make the language more consistent by loosening up some
type checks.

My impression is that PyArg_ParseTuples is pretty flexible and it made
sense for the Python equivalent of PyArg_ParseTuples to be as similar as
possible. Of course one big definition between PyArg_ParseTuples and
__implementedby__ is that the former actually coerces its args and the
latter only checks them. Maybe this is a design flaw....

If there is an obvious way to coerce an object to a type, we should
probably use it. This will make the whole system's behavior more
predictable. But this doesn't work:

 coerce(5, types.FloatType)

In general I don't know how to try to coerce objects to types. I only
know how to coerce two objects to some common type.

> - Your test for Float values that accepts ints is also bad news, at
>   least until integer division is fixed.  You may want to define a
>   separate type IntOrFloat, for those cases where the programmer
>   asserts that either type is fine, and another IntOrFloatOrComplex.

Not entirely happy with that design!!! I'd rather change the language
(which we already intend to fix) rather than hack up the type system.

> > def findInterface(iface, obj):
> >     ifaces = getattr(obj, "__interfaces__", None)
> >     # don't make this mutually recursive on
> >     # Sequence.__implementedby__!
> >     if type(ifaces) in (types.ListType, types.TupleType):
> >         return iface in ifaces # multiple interfaces case
> >     else:
> >         return iface is ifaces # single interface case
> 
> This helper function is steeped in irrelevant implementation detail!

I'm implementing something! I have to put in all of the details required
to make it work. It's supposed to be a prototype not pseudocode.

> - Your assumptions about sequences, mappings etc. are also pretty
>   naive.  operator.isSequenceType() and .isMappingType() return true
>   for all class instances regardless of what they actually implement,
>   and should this be avoided.

I had an explicit check for InstanceType-ness but accidentally deleted
it. I thought I had incorporated it into findInterface. I'll put it back
in. 

Here's Sequence, fixed up:

class _sequence:
    "Any kind of sequence"
    def __implementedby__(self, obj):
        if findInterface(self, obj): # if an object claims to support
            return 1                 # the protocol, we trust it!
        elif type(obj)==types.InstanceType:  # no safe way to know if an
instance
            return 0                   # supports the protocol 
        else:
            return operator.isSequenceType(obj) # safe for C-types
Sequence=_sequence()

> - One way to go would be to have explicit ways to say "x is any
>   Sequence", "x is a List", "x is any Mapping", "x is a Dictionary".

We do:

def foo(x: Sequence, x:ListType, x:Mapping, x:DictionaryType): ...

I haven't implemented the part that checks type objects (or class
objects, for that matter). Here's a new version with an implementation
for that:

def experimentalAssertTypes(dict):
    # this is VERY ROUGH
    # for one thing it should use variable names from the caller,
    # not a passed in dictionary!
    for val, typ in dict.items():
        if type(typ) in (types.ClassType, types.TypeType):
            if not isinstance(val, typ):
                raise TypeError(val, typ)
        elif typ.__implementedby__(val):
            continue
        else:
            raise TypeError(val, typ)

> - But note again that Sequence-ness and Mapping-ness are ill-defined.

I agree. This comes back to the issue of interfaces. I think that the DC
guys have made some progress on a standard type hierarchy, haven't they?

> In short, it looks (and I am as surprised as you are!!!) like we will
> need to agree on the Python type hierarchy before we can ever hope to
> agree on any kind of type assertions.  

Speak for yourself! :) I've tried to define this type hierarchy twice. I
decided to pursue with Tim's suggestion because it provides a powerful
(Turing-complete!) way of defining these types. In my opinion,
typecheck.py is our type definition document for now. We'll haggle over
the definitions of the classes and then we'll write a PEP that reflects
our decisions.

It sounds backwards but interface defintion always requires a formal
syntax (IDL, ODL, PyDL). In this case our formal syntax is Python
methods...

-- 
Python:
    Programming the way
    Guido
    indented it.
       - (originated with Skip Montanaro?)