Thursday, March 24, 2005

Facial hair, functional programming, and static typing

We arrived at Guido's keynote in time for him to explain why he had a beard. He started it because he wanted to shave a few minutes off his schedule during a beta crunch, but he kept it because he liked having his co-workers call him professor.

There was a brief discussion about decorators -- why @prefix syntax won and why there are no class decorators. I thought the choice was obvious given the candidates last year, although I didn't mind the C# syntax either.

Signs of Python's popularity: InfoWorld survey shows python use grew to 14% from 8% the year before. Burton Group wrote a report in "P languages" that recommended the use of Python. Python won a Jolt productivity award -- the runners up honor. We discussed what to make of the 14% statistic a few months ago; based on an gross estimate of the number of programmers survyed, it seems like there are 750,000 to 1 million Python programmers. (Some other back-of-the-envelope estimates come up with the same result.)

Python now has a Python security response team. Guido has subscribed to the bugtraq list. It was interesting to hear him acknowledge that security was a serious issue. He used to be completely uninterested, because, I think, he didn't expect a random attack to have any effect on him.

Guido started talking about Python 3000 in 2000. He said he always imagined it as a release that was three years off, and it still feels that way. He maintains, though, that Python 3.0 will be incompatible in several ways: new keywords, some builtins removed, "classic classes" removed. He said we're not going to do a Perl 6 for Python, which lead to some applause. "Because we didn't get it so wrong the first time," he said.

Guido plans to focus on changes to the language and library, but not the implementation. There are a ton of people working on CPython and other Python interpreters on other virtual machines.

Guido talked a bit about functional programming -- adding any and all builtins to Python 2.5. He discussed any() at length, because he decided it will be a predicate and not a function that returns an element from the sequence.
def any(iter):
for elt in iter:
if elt: return True
return False
It seems to me that any() should return an element of the sequence or None, which isn't an option Guido discussed. None could never by an element returned from the sequence, because it is False. It makes sense for the empty sequence, which was one case Guido worried about. At the end of the day, any() is so short that it is easy to write your own.

It's seems uncontroversial to remove map, reduce, and filter, perhaps leaving them in an extension module. It's quite a different issue to remove a lambda. One option is to find a way to define anonymous code blocks, although most of the uses of anonymous code blocks in Ruby correspond to uses of generators and yield in Python. I think the key issue isn't whether we can make the function anonymous, but that you can write a function in an expression context. Guido later commented that the naming issue wasn't very important.

Guido talked a little about Numeric issues, which don't hold my attention. Tim Peters and Eric Jones had an extended conversation about Numeric at lunch. There are a wide range of user expectations: Should divide by zero raise an exception or return infinity and should it print a warning? The decimal module gives all three options, but getting consistent behavior for these issues across all platforms is really difficult. C89 and C99 don't provide any useful guarantees about numeric issues, so Python's implementation doesn't have a good place to start. (It's ironic because, as Tim noted, all hardware has implemented IEEE 754 since the mid 80s. We just don't have language or library support for accessing the hardware features.)

Guido's current thinking about "static typing" is that programmers could write type annotations that would check types at runtime or even coerce ("adapt") an object from one type to another.

"My favorite classic programming language is Pascal." The very limited support for nested functions in the original Python stem from one of the things he didn't like about Pascal. (Dave Hanson wrote a paper on the same issue: Is Block Structure Necessary?.)

"On form of adaptation or another will make it into 2.5 or 2.6."

He discussed typechecking and generics, but didn't have a practical scheme for checking generic types at runtime. One suggestion was to use it only for documentation, but that seems pointless to me. If the documentation isn't automatically checked, it will be wrong some of the time. The fact that there is tightly integrated syntax won't help at all in this respect. To my mind, if the typechecking doesn't check some static property of your code, I'm not interested in it.

Guido: I'm still interested in exploring this feature, but it's far from clear that it will go into the language.

There was lots of applause for the suggestion that we focus less on type annotations and more on type inference. I think that's an odd position to hold, because it finesses the hardest problem -- the actual type system. What kind of types do you try to infer for a program? What kind of errors are you trying to detect statically?

1 comment:

Matthew Blecker said...

Returning None for no matches was what first came to mind for the any() dilemma for me as well. I think Guido's issues with it were twofold:

1) He wants any() and all() to have as similar usage/interfaces as possible.

2) Possibly returning None adds another type that could be returned by any() if it normally returns an element of a sequence containing a single type. That seems to be an accepted and common practice in Python, but with all the talk (including his own) of static typing, type inferencing, and the like, that could change. (Or not, if Python stays completely dynamic, which would be fine by me.)

Those were both from memory of things he said before his talk, so take them as the hearsay they are.

Another possibility which came to mind for situations like this is to use exceptions as part of the standard interface. To keep any() and all() consistent and let them return members of their argument, they could raise an exception to indicate that they failed.