A Pragmatic Case for Static Typing

Roy Smith roy at panix.com
Mon Sep 2 09:37:53 EDT 2013


In article <52245df4$0$2743$c3e8da3$76491128 at news.astraweb.com>,
 Steven D'Aprano <steve at pearwood.info> wrote:

> One factor I don't see very often mentioned is that static typing 
> increases coupling between distant parts of your code. If func() changes 
> from returning int to MyInt, everything that calls func now needs to be 
> modified to accept MyInt, no matter how similar MyInt is to int. You have 
> to make changes just to satisfy the compiler.

This really ties in with what I was getting at in:

Message-ID : <roy-DFB5E5.20525231082013 at news.panix.com>
Subject: Re: Interface and duck typing woes
Date: Wed, 28 Aug 2013 21:27:34 -0400

Every interface requires certain things and promises certain things 
(i.e. the contract).  At some point, the caller and the callee have to 
agree on what's required, what's allowed, and what's a bug.  There's 
lots of ways of doing that.

At one end of the spectrum, there's the type bondage languages like C++ 
and Java.  But even there, you have things like:

double sqrt (double x);

which only tells part of the "what's required" story.  For the rest of 
the story, you have to resort to reading the natural language 
documentation:

"If the argument is negative, a domain error occurs"

At the other end of the spectrum, there's Python's duck typing, which 
says, "Give me something, and I'll let you know if I can't deal with 
it".  But we're still not playing 20 questions.  Presumably, the callee 
gives you some kind of hint about what sort of duck they're expecting.

It seems to me that any time you can encapsulate knowledge about the 
contract into something that's machine readable, you've added value.  
Now you can have automated tools do something useful with that 
knowledge.  Maybe that means raising an error at compile time, or when 
you run a static analysis tool.  Or, more apropos to Python, at function 
call time using pep-3107 annotations.

So, let's go back to your original statement (requoted here for 
convenience):

> One factor I don't see very often mentioned is that static typing 
> increases coupling between distant parts of your code. If func() changes 
> from returning int to MyInt, everything that calls func now needs to be 
> modified to accept MyInt, no matter how similar MyInt is to int. You have 
> to make changes just to satisfy the compiler.

It's not that static typing has increased coupling.  The coupling has 
always been there, it's just that now it's being enforced at compile 
time.  What's the difference between int and MyInt?  I'm going to 
speculate that ints are 64 bit 2s-complement binary and MyInts are 
BCD-encoded fixed-width character strings with leading blank padding.  
The problem is NOT that static typing forced me to change every place 
that calls func().  The problem is that func() has fundamentally 
changed, and THAT is what's forcing me to change all my code that calls 
it.  The static typing just lets me communicate that to the compiler.

I actually think Java was on the right track with interfaces.  They are 
essentially duck typing enforced at compile time.  Rather than saying, 
"You must pass me a Duck", you're saying, "You must pass me something 
that has quack(), waddle(), and poop() methods".  If I later change 
func() to also call your_object.fly(), I've changed the contract on you.  
And whether you know about it or not, your code and my code are coupled.

The difference is that with static typing, you find out about it 
quickly, and with pythonic duck typing, you may not find out about it 
until three years later when some unusual condition finally causes the 
fly() code path to get executed and you've long since moved on to 
another project.

The next step is to understand that the real contract may be more 
complex than can be easily encapsulated in a type or annotation or 
whatever.  The contract may be:

"You must pass me something that can quack(), waddle(), and poop().  In 
addition, if it's a full moon, it must also be able to fly()."

So, the big question is, how should I specify that to a human, and how 
should I specify that to the computer?



More information about the Python-list mailing list