|ePolyglot: Examination and development of multilanguage programming using Eiffel, Python, and Haskell|
The process of developing the ePolyglot library was torturous in spots but exciting overall. While we don't think that multilingual programming will really become a mainstream practice, it's exciting to note that it's possible--and with the advent of Microsoft's .NET platform, which promises language interoperability, this could well become a more mainstream practice (although, in the interest of interoperability, one hopes that the .NET project will become multiplatform in time).
The lessons learned, aside from the simple knowledge of how to go about doing this, are encapsulated in a few overarching concepts:
Python is fun to work with. A rather pithy-sounding lesson, this has some broader implications. A dynamically-typed, highly interactive language with some reflective capabilities isn't just easy to use, it's fun. And a tool which is fun to use is a tool which will be used. Python's readily-understandable syntax combined with its powerful library make it a popular choice for scripting standalone applications much as Visual Basic's ease of use made it a popular standalone development tool. But as an embedded language, it could well allow application developers to add that element of fun to extending and using their applications, and anything that can do that deserves some attention, as the multitude of user additions to Microsoft's Office suite can attest.
Dynamic typing can be sneaky. A number of times during the development of the Python libraries and scripts, as well as the Eiffel shadow classes that go along with them, we were caught unawares by sneaky little errors that crept in--sneaky because they could have been caught by static typechecking. In particular, the interface between Eiffel and Python could well produce some peculiar errors because Python is so loosely typed at the source code level. So it's worth noting that Python's ease of use comes at a slight price in the form of less-safe typechecking at the source level. That's not necessarily a bad thing, but it should be used with caution.
Static typing can be frustrating, but very handy. The flip side of the dynamic typing coin is that static typing and whole-system analysis can be rather annoying during development, because it can raise errors which could seem to be miniscule; in particular, the static typing of Haskell, which even distinguishes between "Int" return values (from a pure function) and "IO Int" values (from a function with possible side effects) can drive a developer to distraction. But in each of the cases where the compiler gave us a static typing error, it was a real error, with real implications if it was left in production code. Overall, we are very much for static typing as a way to catch potentially crippling errors as early in the development process as possible.
Type inference is very nice. Haskell, though strictly and statically typed, also employs a great deal of type inference, where the type of a symbol is determined by its context. In a way, this is the best of both worlds--the developer doesn't have to worry about declaring the type of every symbol he uses, yet still benefits from type analysis which can catch sneaky problems like mixing Ints and Doubles.
Pure functions are very nice indeed. Functional languages revel in the lack of side effects from pure functions, which change nothing in the state of the world or in their arguments. Neither Python nor Eiffel offers this sort of guarantee; C and C++ only come slightly closer, with their use of const-- a keyword which doesn't quite mean the same thing. It gives a great feeling of safety to know that a feature call to a pure function will only produce a result and not cause potentially erroneous state-changing behaviour. Of all the lessons to be learned from functional programming, the absolute separation of state-changing functions and pure functions (called "command-query separation" in other circles [Meyer97]) is one of the most simple and important ones.
Most tools don't like each other. We used a remarkable array of tools in this project--SWIG, SmallEiffel, HaskellDirect, Python, make, autoconf--and none of them were designed to work with each other, having to be massaged together through the use of Makefile targets. It is a tribute to the make application that such a thing was even possible, but in a few cases--most notably the effort to link all three languages together--the problem became really irritating. We never found any way to pass optional linker arguments through ghc, a simple addition to the compiler that would have saved quite a bit of time and frustration. For the moment, multilanguage programmers must still face some significant--if surmountable--hurdles.
We have learned a great deal from the effort to make multilanguage programming in Eiffel, Python, and Haskell a reality. While the end result may not be suitable for most production environments, we hope to at least make it possible, and to encourage others to give multilanguage programming a try. While far from perfect, it at least gives developers the chance to leverage the strengths of different development environments in a single application, rather than stretching one language to fit all problems.