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

Martijn Faassen faassen@vet.uu.nl
Fri, 21 Jan 2000 04:06:36 +0100

Greg Stein wrote:
> Okay, now we get to the big "HUH?!" in this post...
> > You'd have to leave out all type declarations in the code that *uses*
> > instances of your classes, then.
> > 
> > class Foo:
> >     def a(self):
> >         pass
> > 
> > class Bar:
> >     def a(self):
> >         pass
> > 
> >     def b(self):
> >         pass
> > 
> > # 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?

> What else *should* happen here? I cannot imagine any other reasonable
> response from the compiler.

Me neither, really. :)

> 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.

> > # so we have to do this in order to be able to use both Foo and Bar here:
> > def use3(obj):
> >     obj.b() # run-time error! 
> Yes, a run-time error. What's your point?

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.

> > # 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

then you have essentially the same problems as the other people who responded
to my mails listed. How do you get around those problems? Or is it just
intended not to be used often enough to be a problem?

> I don't understand your point. The behavior is all very well understood
> and quite clean.

I must be misunderstanding something if my above speculation is the case
(it may very well not be) -- if it is, I'm not quite sure how their
valid objections to my different spelling of the same thing make sense..

> > Isn't this a good intermediate step between having an explicit interface
> > and not having any interface at all?
> I have an idea of what the compiler should be doing (as specified above)
> and think that it works very well. I do *not* understand what you are
> saying.

I understood that. I must've been expressing myself really badly tonight.

> 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?

> > [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.

> 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.

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.

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. 

Now, I'm reaching the conclusion that if I understand the semantics of '|' 
right then that the thing I was talking about already exists. It may also
be possible that my head is too fuzzy to make sense of things anymore. :)

Did that explain my wacky advocacy at least a little, Greg?