[Types-sig] Re: what the heck? (was: Static typing: Towards closure?)

Greg Stein gstein@lyra.org
Thu, 20 Jan 2000 19:32:27 -0800 (PST)

On Fri, 21 Jan 2000, Martijn Faassen wrote:
> Greg Stein wrote:
> > > # this doesn't seem to work right 
> > > def use1(obj: Foo | Bar):
> > >     obj.b() # what happens here? Is this allowed? or is an intersection taken?
> > 
> > It fails. Period. You have stated that "obj" might be a Foo, and we know
> > that Foo does not implement the "b" method.
> This would mean that an intersection of the interface of class Foo and
> Bar is taken, and if you call any method that's not on either, there
> is a compile time failure.
> In effect this is a different way to spell implements, except that the
> '|' makes it possible to do it ad-hoc.
> This means that something like
> typedef Alpha = Foo | Bar
> is creating the same thing as the 'implements' proposal?


> Or am I understanding this completely wrong?

In your original statement, Alpha is the intersection of the Foo and Bar
interfaces. The above typedef is very different. Specifically:

  def f(x: Foo|Bar):
  def g(x: Alpha):

In the former case, f() might use features of Foo or Bar after determining
which you passed. In the latter, it is only using Alpha features. *Very*
different semantics.

> > What else *should* happen here? I cannot imagine any other reasonable
> > response from the compiler.
> Me neither, really. :)

And this is what gets me. Why the heck bring it up? Just to give us
something to read? To make our brains spin some cycles to figure what you
were trying to say, when you really weren't?

Sorry. I didn't get much sleep last night, so I'm probably being a bit
harsh. But I do tend to dislike having to pore through long emails looking
for a point, only to find nothing.

> [snip]
> > What's the big deal? Why is this behavior not reasonable?
> No big deal; the behavior is perfectly reasonable, I never claimed
> it wasn't.

See point above.

> We wanted to have the advantages of static-type checking, so I was wondering
> if some intermediate system was possible where you can have some of the
> features of static type checking without having the full-blown system. This
> in order to apply some static type checking to Python code that's altered
> only minimally from its current form.

I think the current proposal, embodied in Guido's paper and slide deck
sufficiently answer the "intermediate" case.

> > > # now, if Foo and Bar both stated they implemented the interface Alpha, 
> > > # the compiler could deal with this:
> > > def use4(obj: Alpha):
> > >     obj.b() # compile time error
> > 
> > We don't need Alpha to do this. The original Foo|Bar did the same.
> You're probably right and I'm just looking at it in an upside-down way.
> If you can create implied interfaces (intersections) using something like:
> typedef Alpha = Foo | Bar

This is an implied interface, but different from the output of your
original proposal.

I think that I wasn't clear in my response above. "You don't need Alpha
[to generate the error on obj.b]". In other words, you need need the
implied construction of Alpha to solve the obj.b problem.

> > Yes, there is an implied interface from the definition of Foo, and the
> > invocation "obj.b()" fails when used against that implied interface.
> > 
> > BUT: we can entirely omit the word "interface" from this point, and just
> > state that we know "obj.b() will fail because the Foo class does not
> > define a 'b' method."
> >
> > Eliminating the word "interface" from the discussion is Guido's current
> > position. I believe this is entirely possible. At an implementation level,
> > I believe there might be an interface-like object, but that's for another
> > discussion.
> If you include typedefs that interface-like object is named. Or is this a
> typedef that is not allowable?

The class object serves the same purpose. There is no need to expose the
interface object. Specifically:

  class Foo:

  a = f() ! Foo

In the above example, Foo is a name pointing to a class object. The
type-assert uses the class object, rather than its implied interface to
perform the type-check.

So: we don't need the word "interface".

> > > [note: it would also be possible to give Foo and Bar a common baseclass and
> > > require that type to be used:
> > > 
> > > def use5(obj: Common):
> > >     obj.b() # compile time error, not defined by Common
> > 
> > Yes. What else is supposed to happen?
> It's completely valid; I wasn't saying anything was _wrong_ with this.

See point further above.

> > Really: where are you going with this? I just don't understand.
> I was coming to this from the point of view of a (out of his mind :) user.

And coming from a short sleep period, I was getting agitated :-)

> When writing Python code currently, the dynamic typing allows you to 
> program without a lot of the rigidity that a static typing system brings you.
> This rigidity can be good for OPT and ERR, but can be bad for PRO, rapid
> prototyping/speed of development. One tends to get side-tracked into issues
> of which type to use where instead of actually solving the problem at hand,
> bad for PRO.

Sure. So don't use them. As Guido has pointed out, you will retain the
exact same, rapid development capabilities as before. The compiler might
issue a few errors that it didn't before, but that is simply because you
*did* make an error.

You can continue to write huge bodies of code without a single

Personally, I will primarily use them in function definitions (such as  
"def foo(x:int):"), so that I can get asserts on function-entry.

> Still, static typing can be nice as well. What I was grasping for was some
> way to use the typechecking system while at the same time being relatively
> little bothered by the rigidity. So, a way to have _some_ ERR (and DOC),
> while keeping a lot of PRO. 

Just use less. There is no "poisoning" that will require you to use
declarations everywhere. Use it in key places where it helps. Avoid it in


Greg Stein, http://www.lyra.org/