[Types-sig] RFC 0.1

Christian Tismer tismer@appliedbiometrics.com
Tue, 14 Dec 1999 16:57:40 +0100


Greg Stein wrote:
> 
> On Mon, 13 Dec 1999, Paul Prescod wrote:
> > I did evaluate your proposal but it seemed to me that it was solving a
> > slightly different problem. I think as we compare them we'll find that
> > your ideas were more oriented toward runtime safety checking.
> 
> True, but I might posit that (due to Python's dynamic nature) you really
> aren't going to come up with a good compile-time system. That leaves
> runtime.

This is very true. Are you completely moving away
from type declaration, or do you still propose an
  expr ! typeid
notation?

...
>   a = b
> 
> We suggested that type checking is defined and applied to the value (b),
> rather than associating a type with "a" and performing an assertion at
> assignment time. The concept of "this variable name can only contain
> values of <this> type" is a standard, classical approach. We didn't think
> it applied as well to Python (for a number of reasons). If you're doing
> type inferencing, then you are actually tracking values -- the types
> associated with a name are very artificial/unnecessary during type
> inferencing. For example:
> 
>   a = [1, 2]
>   foo(a)
>   a = {1: 2}
>   bar(a)
>   a = 1.2
>   baz(a)

One could have both behaviors at the same time, I think.
Type restriction would be a property of the involved namespace.
The namespace responsible for the assignment could be an 
extended dictionary object with the desired rules defined.

...
> For the case of:
> 
>   if condition:
>       x = 1
>   else:
>       x = "abc"
> 
> I would say that the type of "x" is a set, rather than a particular type.
> If you're going to do type-checking/assertions, then any uses of "x"
> better be able to accept all types in the set.

Allow me a question about types:

Where are the limits between types, values, and properties of values?

Assume a function which returns either
[1, 2, 3] or the number 42.

We now know that we either get a list or an integer.
But in this case, we also know that we get a list of three
integer elements which are known constants, or we get
the integer 42 which is even, for instance.

So what is 'type', how abstract or concrete should it be,
where is the cut?

> I believe that Python is too rich in data types and composition of types
> to be able to add *syntax* for all type declarations.

At the same time, Python is so rich from self-inspection that
writing a dynamic type inference machine seems practicable,
so how about not declaring types, but asking your code about its
type?

I could imagine two concepts working together:

Having optional interfaces, which is a different issue
and looks fine (Jim's 0.1.1 implementation).

Having dynamic type inference, which is implemented by cached
type info at runtime.

(I hope this idea isn't too simple minded)
Assume for instance the string module, implemented in Python.
It would have an interface which defines what goes in and
out of its functions.

At "compile" time of string.py, type inference can partially
take place already when the code objects are created. The interface
part creates restrictions on argument values, which can be used
for further inference. It can also be deduced whether the return
values already obey the interface or if deduction for imported
functions is necessary.
This info is saved in some cache with the compilation.
Changes to the module object simply break the cache.
When I dynamically redefine a piece of the module where it
depends of (say I assign something new to "_lower"), then
the analysis must be carried out again, recursively invalidating
other cached info as necessary.

Well, this is an example where I think the restriction to
type checking of expressions still applies, but something more is
needed to trigger this check early.
The involved namespace object is the string module's __dict__,
which should know that it is referenced by this expression:

def lower(s):
	res = ''
	for c in s:
		res = res + _lower[ord(c)]
	return res

And by assignment to the name "_lower" in this case, it could
invalidate code object lower's type cache. lower can no more
assure that it will return a string result and will trigger
its interface object to re-check consistency. The latter
will raise an interface_error if the rule doesn't match.

It remains an open question for me how deeply possible
values should be checkable, i.e. "this arg has to be a list
which is not empty". Minor point, maybe.

Did I make some sense, or am I off the track? - chris

-- 
Christian Tismer             :^)   <mailto:tismer@appliedbiometrics.com>
Applied Biometrics GmbH      :     Have a break! Take a ride on Python's
Kaiserin-Augusta-Allee 101   :    *Starship* http://starship.python.net
10553 Berlin                 :     PGP key -> http://wwwkeys.pgp.net
PGP Fingerprint       E182 71C7 1A9D 66E9 9D15  D3CC D4D7 93E2 1FAE F6DF
     we're tired of banana software - shipped green, ripens at home