Sponsored Link •
I'm glad to see the first beta of the so-called Python 3000. But for a version that's supposed to break all the rules to become better, I'm not seeing what I think is most important.
As time passes I appreciate Ruby more and more; hats off to Ruby, it (via Rails) has brought dynamic languages into the mainstream. But I've spent far more time with Python so I'm still much more productive with it, and remain a huge fan of the language.
Because I'm invested in Python, there are things I hoped to see when Guido first started talking about Python 3K and how it had permission to completely change the rules in order to create a better language. We did this once before in Python 2.2 or 2.3: introduced backwards-incompatible changes that would break old code. I remember there was a lot of trepidation and concern and scaffolding to try to gentle the transition.
But it turned out to be a non-event. The people who didn't want to change stayed with the earlier version of the language, and those who moved forward saw the costs and the benefits, and opted for the benefits. Apparently Ruby is also planning code-breaking changes to the language, primarily to take out the Perl-isms (a move I heartily applaud, and one that makes Ruby that much more attractive). And the Java designers should certainly take notice, especially because the people they are so worried about offending with language incompatibilities are still using Java 1.1 with no plans to change; they aren't even paying attention to these discussions. In the meantime, Java continues to ossify, pursuing its endless quest to produce the perfect program through static type checking, by adding more and more. The good thing is that people are finally beginning to see that static type checking is useful in small amounts and intrusive in large amounts (although I suspect this realization won't reach the main group of Java designers for years to come). The bad thing is that, in the meantime, we get abominations like Java "generics"; via daily use people are finally beginning to see what I tried to explain years ago -- Java "generics" are far more painful than helpful, just like checked exceptions. But I digress.
In this article I talk about the issues that I consider very important, and worth code-breaking language changes, that I don't see happening in Python 3K.
I know that true concurrency support -- the ability to run pieces of a program on multiple processors -- is hard in a dynamic language. Although they both have threads, neither Python nor Ruby is able to actually allocate those threads to multiple processors. The threading is just for code organization and to handle blocking operations. Ruby and Python are prevented from using multiple cores because they both suffer from the global interpreter lock problem.
But right now we are on the brink of a huge potential gain for dynamic languages, with the advent of multi-core systems. Here's the place where the performance impact of dynamic languages, so often used as an excuse to avoid them, could be erased. Multicores could be what brings dynamic languages into their heyday, and could relegate languages like Java and C++ as "what you use for writing small pieces of your application, only if you absolutely must."
The solution can be creative, as long as (A) it's simple to use and (B) it's reasonably idiot-proof; I'm the first to admit that I'll probably never be able to create a correct threaded program in C++ or Java, despite years of study. It's just too hard.
From a programming standpoint, agents are still the best thing that I've seen. The language provides support to help the programmer create agents, and for the agents to automatically handle their own concurrency and defend their memory. There's no shared memory outside the agent, every change happens via an input queue, and each message is executed to completion rather than trying to execute multiple messages together. See the Scala Language for more details on agents.
One solution I can imagine that might work is to take the BeOS operating system's approach, which is to make creating OS processes very easy. If there's no way to get rid of the GIL even in Python 3K (but there might be a way, given enough language changes), then perhaps it would be possible just to create a new Python image in another process, and make it easy to communicate with that process. Thus, creating an agent would create an OS process, and communicating with the agent would actually send messages through OS pipes.
That's just one suggestion, but the problem needs to be solved or some other dynamic language will solve it, and we'll be forced to go to that language in order to use all the cores that are becoming available (Scala agents have already produced what seems to be the best solution around, especially because Scala has tried to solve the syntax-horror problems that plague traditional functional languages -- and yes, before you write, I've looked at Erlang, which is great at solving some problems but it isn't the future that Scala promises).
I know it's hard. But I don't want to hear that it's impossible to fix the GIL. I don't care, I need to run programs that use multiple cores and I'd sure like to use Python to do it.
I'm hoping that this is just an issue of "waiting for maturity," but we need to make support for Python Eggs and Easyinstall part of the python distribution. Easy installation and update of library components should not require effort or be a distraction.
This is connected to the previous point, but it's important on its own. We need a one-button solution to deploying applications, producing a package that gives consumers a one-button solution to installing them. Too many people have avoided Python apps the same way they avoid Java apps, because the installation process is confusing. And don't tell me "it's not hard!" Yeah, it's not hard for you, the computer geek, you love doing stuff like that (recompiling your Linux kernel seems like the most obvious thing in the world to you). But the average user gets flummoxed the first time the install process asks them a question, and forget it if it involves multiple steps and installations.
This is something I really hoped to see in Python 3K, but the beloved self seems to be hanging on.
self is inappropriate noise in a language that lays claim to clarity and simplicity. No other mainstream OO language requires it everywhere like Python does, and it's a hurdle for people who try to come to Python from those languages. Maybe it's a significant reason that Java programmers seem to be more comfortable with Ruby; Ruby takes care of it for you just like C++ and Java do.
Although it still gets use, I don't think the built-in Tcl/Tk would be anyone's choice as a standard Python UI library if we were deciding today. This is especially true when you look at systems like Flex and Silverlight (and presumably JavaFX, but I haven't yet seen that), which are designed to solve the UI problem first.
Why not create the best of all possible worlds and leverage those systems -- optimized to create UIs -- on top of Python the same way that we've used Tcl/Tk in the past?
Event support, described below, would probably make this a lot nicer, but I'd at least like to see a solution that allows me to transparently talk back and forth to the UI subsystem in my application.
Reusing library components is still the most productive way to leverage any programming system, and Python has always made it far easier to use libraries than most other languages I've worked with -- certainly much easier that C++ or Java. I'm used to using a text editor because even naked, the language is vastly more productive than Java, but people have come to expect a much more interactive development experience. IDEs with context assistance may seem like icing on the cake, but they really do increase productivity and Python 3K is the place to support this.
We've only scratched the surface of what's possible with an interactive software development system, and most of these are variations of a single idea: context help. But context help is just a slightly smarter version of online help -- it removes a step from the searching process, and will sometimes paste in rudimentary code fragments for you. Although that's been extremely useful, I think it's possible to create a far more revolutionary development environment, one that could even be said to practice "inversion of control."
I think the libraries themselves need to get smarter and support greater interactivity. I want the component to tell me what it does, how to use it, and even to reach out and wire itself into my program (for example, by looking at the available variables and putting candidates into its argument list, with drop-down menus that allow you to select appropriate alternatives). In the best of all possible worlds I would never have to look up documentation for a library component again, because the component would insert itself properly into my program and answer any questions that I have by itself, without me looking anything up -- for example, if it was missing an argument, it could suggest the way to create the object that it needs for that argument.
The information necessary to create a "smart library" is in the same vein as JavaDoc; a little language that allows you to expose information about your library component. But JavaDoc is really an early experiment, and I think we should standardize the way that you describe the information that your component exposes to a development environment, and even the way it does command-completion. This way you could hover your mouse over an identifier and do all kinds of things to it.
I think it would even be possible to integrate tests into the library component, maybe deeper tests that could test the way that you've used the component. But even if the new approach just provided tighter coupling with unit tests (and ideally, a less noisy syntax for unit tests), that could be a great improvement.
Optional static typing, similar to what Flex uses, seems to be in the works for Python 3K, although Guido has cleverly disguised it as "any information that you'd like to add, doesn't have to mean anything." This may solve a major part of the problem with Python as it does with Flex -- the FlexBuilder development environment gives you warnings (and doesn't provide extra information) when you don't provide the optional static typing, but programs compile just fine without it. With the extra type information, you get context assistance in the IDE.
I've been using the word "component" rather loosely; true component support seems to require direct language support for properties and events. Although it's not formal, Python has a decent property mechanism, but event support is not a part of the language and is relegated to third party libraries like Twisted, which is interesting but hard to pin down (I spent a few weeks once working with what I thought was the main thrust of the Twisted library, only to discover that the creators had decided that was a dead end and were working on something else).
As mentioned before, there is no really official UI library for Python, so there hasn't been pressure to support an eventing system that would make it easier. And I don't even know if that's a good idea -- with support for simple coupling to Flex, Silverlight and JavaFX we may forever remove the need for Python to have its own UI library.
But in general, if each Python process does indeed need to be single threaded from a processor standpoint, then built-in eventing could at least help produce the organizational effect that you get from breaking a program up into individually running pieces.
Although Domain-Specific Languages (DSLs) have gotten a lot of press lately, creating little languages to solve specific problems has always been one of the more powerful weapons in a programmer's toolbox (the Interpreter design pattern is an example of this). This is another area where Ruby has a leg up, although in the grand scheme of things Ruby's DSL support is fairly limited.
There's even a new language called Converge, inspired by Python and with Pythonic syntax, that is primarily designed to create DSLs. This could be used as inspiration for native DSL support in Python 3K.
What features do you think have been left out of Python 3K? What problems will you still be unable to solve with it?
|Bruce Eckel (www.BruceEckel.com) provides development assistance in Python with user interfaces in Flex. He is the author of Thinking in Java (Prentice-Hall, 1998, 2nd Edition, 2000, 3rd Edition, 2003, 4th Edition, 2005), the Hands-On Java Seminar CD ROM (available on the Web site), Thinking in C++ (PH 1995; 2nd edition 2000, Volume 2 with Chuck Allison, 2003), C++ Inside & Out (Osborne/McGraw-Hill 1993), among others. He's given hundreds of presentations throughout the world, published over 150 articles in numerous magazines, was a founding member of the ANSI/ISO C++ committee and speaks regularly at conferences.|