Polyglot programming

This page features a short comparison and some links on writing fast, (mostly) compiled code for efficient scientific computations which can easily be called from Python. We review several candidate languages, namely C, C++, Fortran, Cython, Numba, Nim, Rust, D, Chapel and Julia.
For simple problems, Numba is very useful to speed up code execution, but for more complicated tasks, other approaches are necessary. Cython seems to be the natural choice, but the translation to C code and consecutive compilation is rather disruptive in a Pythonic workflow. Cython generated code is sometimes slightly slower than other languages like C or Fortran, but usually not more than a factor of two. C, C++ and Fortran can easily be called from Python but are not exactly nice to work with. Even though C++11/14 and Fortran 2003/2008 improved the situation quite a bit, C++ is still very complex and Fortran shows its age of almost 60 years. Moreover, modern, object-oriented Fortran is not easily callable from Python (and C/C++ for that matter), but needs an additonal layer of wrappers.
Nim is nice in that it has a syntax rather close to that of Python and the Pymod package can be used to auto-generate Python modules that wrap Nim modules. As a compiled language, Nim is very fast but it has certain problems for practical use, e.g., it is still under heavy development, so the language is still changing, but the stable 1.0 version should not be too far ahead. A show stopper, however, is the lack of support for n-dimensional arrays.
Another relatively new, but already stable language is Rust. It features guaranteed memory and thread safety, type inference and good performance. Rust is a systems programming language intended to be a memory safe replacement for C/C++ and in some respects somewhat lower level than Nim, Chapel or D, and might therefore be slightly more complicated to use. Moreover, the Python interface is CFFI based (C Foreign Function Interface), which is fast and flexible but not necessarily the most pleasant to use. Still, Rust is much simpler than e.g. C and C++ and certainly preferable if one has to choose between the two.
A language that has been around for somewhat longer but is otherwise similar to Rust is D. It is fast, robust, easy to use. However, just as NIM, D seems to lack support for n-dimensional arrays, which is a show stopper for scientific computing.
A language, specifically designed for scientific computing, is Chapel. It shares the pleasant feature with D (fast, robust, easy to use), but offers native support for n-dimensional arrays. Moreover is is easy to call from Python and has the advantage of featuring not only local parallelism, but also cluster-level parallelism.
Even though Rust, Nim, D and Chapel are statically typed, they have very strong type inference, but at compile time, therefore offering flexibility while retaining good performance. Variables are statically typed, but not explicitly. Besides, they also support overloading and static dispatch, which is a both fast and clean way to write flexible algorithms which can deal with several data types.
Currently, the most interesting language for high-performance and scientific computing seems to be Julia, which features a nice and clean syntax, and very good performance. Similarly to Cython, the difference in execution time compared to C, C++ and Fortran is rarely more than a factor of two, usually less. Productivity (measured in lines of code necessary to accomplish a given task), however, is tremedously improved over C, C++, Fortran and even Cython. Julia is still under heavy development, implying that the language is not yet fully stable, but breaking changes are rare. The Python interface (PyJulia) does neither seem to be very stable nor very actively developed. So calling Julia from Python is not always as smooth as one would want it to be. The other way around, calling Python form Julia via PyCall, however, works very well and reliably. Many important Python/SciPy packages like matplotlib and SymPy have been wrapped that way and are accessible from Julia. Julia seems to provide the best overall package for writing scientific code. It includes native support for n-dimensional arrays, shared-memory concurrency and high-level distributed memory parallelism. There are bindings for many important libraries like MPI, HDF5, FFTW and PETSc. So instead of calling Julia from Python it seems more effective and more reasonable to write code directly in Julia and call Python if needed, rather than the other way aroud. This also solves the two-language problem, i.e., using some high-level but low-performance language for writing the main program and some low-level but high-performance language for writing numerical kernels. Julia is both, high-level and high-performance, allowing to write very short but still very fast code, providing a flexibility that is rarely found in any other language.

Ressources

Overview over support of important language features

Cython

Julia

Chapel

D

Nim

Rust

C++11/14

Fortran 2003/2008