My answer would pretty much be Haskell, but others are worth to be known, too.
I know many languages and their disabilities.
Most important to me are the following abilities..
- to develop programs fast
- compile to fast running programs
- be platform independent
- read and understand undocumented source easily
- function-names and -types suffice as documentation
- no frustration
To me, Python (like most languages) does NOT answer the first ability, because I want bugfree programs! Im most languages, the development automatically implies the effort to test the program many times. In Haskell, I just try to compile... as soon as it compiles, I feel pretty sure, that every single test will definitely show a bug iff there exist a bug. That means: either it crashes immediately, or it shows an obvious mistake in design, or it runs bugfree. I know Haskell at least since 2002, and I did never have to write a testcase. To test it, the interactive interpreter suffices. It takes longer to make my code compile than to test it.
My last bug (the only bug I remember), was in the NFS-Proxy I programmed in my Diploma-Thesis (=Master-Thesis) in Haskell. It took many hours to find it, and it was a thread that killed itself while updating a global variable to the "NoThreadRunning" value, which was –of course– protected by a semaphor. (To have managed to shoot oneself in the foot in such a way, did feel like winning the lottery, yeah.) I did design it correct, changed half of the design, and was proud of the automatic self-killing-and-respawn mechanism until the first test two or three months of programming later. But after the fix, it worked bugfree as NFS-Client and NFS-Server with file-distribution over multicast.
Other languages:
- C : relative platform independent, but you need to use the std-libs to manage big-/little-endian and 32-/64-bit sizes. It is very very hardware-near, I know only about C-- to be more hardware-near without being assembler. Libraries should be at least made accessible via C to be relative language-agnostic.
- C++ : definitely better than Java. You don't want a garbage collector if you don't need it. C++ has more type-safety and bug-avoidance-design-patterns than most languages (see books from Scott Meyers, http://www.aristeia.com/books.html).
- Java : You combine C++ with slow-to-recover diseases and you get Java. Obtruded garbage collector where you don't want it, half-OOP, less type-safety than C with its praeprocessor-makros (or still recovering), instead of references pointers everywhere (called references, can still be a NULL-pointer in contrast to c++-references) and therefore NULL-pointer-exceptions, OOP design even where it should not be, no "proper tail calls" (epic fail in the design of Java Byte Code) and therefore stack-overflow-exceptions. The frustration level is extremely high.
- CommonLisp/Scheme : Yeah, that's old. It was designed about 50 years ago to proof that it is possible to program in such an abstract way that you do not see the RAM-machine and its assembler below. ProgramCode equals Data, Procedures are Lists of Commands, and you can manipulate Lists because they are data structures itself. This is the foundation of all functional programming languages. The imperative languages did not develop much since then, they are still based upon if+while+for(+goto) and variable-assignments, which is really poor for languages that do not aim for embedded systems like microcontrollers. Anyway, ancient Lisp was not developed to program in and therefore looks pretty ugly. Still, easiest language to learn, not easy to master.
- Erlang : nice scripting language, easy to learn, easy to program multi-threaded (but single-processor) server-programs. It is interpreted and the program code can be exchanged even while the program is running! It is functional and as easy as Python.
- Python : a scripting language that replaces BASH in many ways. It can't be really compiled due to its dynamic types. It was influenced by many functional languages and therefore can juggle with functions better than C/C++/Java. Dynamic types have been the solution to fast prototyping, decades ago: You need to write less code, if the type-correctness is performed in runtime instead of compiletime, because you do not need to specify the types in your code.
- ECMAScript(JavaScript, Adobe ActionScript etc.) : They do have not only OOP but Closures, too, so that they can be used for functional programming. Well, not really because functional programming urges to use tail calls, and ECMAScript (like java) does not have proper tail calls at all. And because no browser supports the programs with infinite stack space, it is one of those Stack-Overflow-Exception languages. The proposal for including proper tail calls in the language definition has poor chances because with that new feature the existing interpreters and jit-compilers need too much redesign.
- Lua : OOP and Closures and proper-tail-calls! Well, it has a good design and allows to influence the code/language itself somehow like Lisp can redesign itself. The language is designed with the goal to be used as scripting language embedded into other programs (like games or browsers or graphic-/3d-/CAD-editors), and it seems to be perfect for that goal. I did not program enough in this language to know how easy it is to learn, because to me it is just not "pure functional" enough.
- Pascal(Obsolete)/Delphi(Borland/Windows only) : It was better than C++, before C++ had templates: Pascal did have explicit typing and explicit casting. It was the time when scripting languages with dynamic types were faster written because they did not need explicit written types. C/C++/Java have implicit casting, which makes them more bug-prone. Pascal had/has double-sized function-pointers in contrast to C/C++/Java, because they did not only contain the pointer to the function-code but also a pointer to the stack frame of the "outer" function; which implies that functions can be nested and have something similar to Closures. (A function has access to the local variables of its outer function, and a pointer to an inner function is only valid as long as its outer function is running.)
- Visual-C++ : It is not C++, but it looks like ("visual"). It has or had many design flaws, like [code]for(a,b,c)d;[/code] === [code]a;while(b){d;c;}[/code] instead of additional putting everything in curly brackets; the difference is the range where the "a" is defined. The solution to that was this line of code: [code]#define for if(0)(void)0;else for[/code] Not everything was implemented in the compiler, like static floats in class-templates (only integral types allowed) as if they were confounded with template-variables. Next problem: Template-variables can be classes which have not only member-variables and -functions but also inner classes/typedefs. In the case of such a type, the compiler needs to know that it is a type, therefore the c++-keyword "typename" is needed. In Visual-C++ this was not properly checked and therefore caused compile-time errors when using apis that did compile before; not used templates weren't checked properly.
- Haskell : Yeah, well, what should I say... I'm still learning it. 7 Years are not enough to properly know all features and language-extensions and the mathematical Cathegory-Theory behind it. Everything else looks like an assembler frontend, compared to Haskell.
The type-casting is explicit (functions are needed to convert) and therefore pretty safe. Like in dynamic typed languages the types do not need to be written explicit, but they are implicit and strong typed instead of dynamic/weak. The type system in Haskell is Touring-mighty and more expressive and easier than the templates in C++ (and D).
If you like to learn some languages, I recommend learning (in this order) any Lisp/Scheme, Python, Prolog, OCaml, then Lisp again in not more than 1-3 days each. Those languages are extremely different and will form your way of thinking.
C++ at least 1 week with Bjarne Stroustrup's book (he is the inventor of C++) and Scott Meyers' books, and then Haskell for about 1 month with "The Craft of Functional Programming". From then on only Haskell and C++. After one year of learning Haskell and writing your own tutorial about Monads, you can call yourself a beginner.
Oh, and at first read this: Beating the Averages (paulgraham.com/avg.html)
It explains why the most used programming languages are not the best, and how to become rich.