The cost of a programming language
We recently had a new UX designer start and as I demonstrated the product we support he asked me an interesting question.
"If given the chance to start the project again, what programming language would I choose?"
This is an interesting question. My instinctive answer is my favorite language. Or one I am currently experimenting with. I then started to give this some deeper thought. Many authors and articles talk about CPU Cost vs Developer Cost. CPU cost is the cost of running the application. Developer cost is how long it takes a developer to write the task. Modern development favors scripting languages such as Python and JavaScript. These languages have a lower low developer cost then C/C++. Most embedded systems have limited resources. Some have strict performance requirements that rule out many languages.
There is a third cost that is often neglected, but is important, especially so in the embedded world. And that cost is the operational cost. What does it cost to maintain the system, to provide updates and bug fixes to the system as time progresses. In my experience this cost is rarely considered if not neglected altogether. For many years it was irrelevant, there were two options in the embedded world, C and assembler. I know many people who like assembler but it doesn't scale the same way C does. So for many years C was the only choice. Recently there is growing support for feature restricted C++ (no exceptions for example). Python and JavaScript now contain interpreters for ARM processors. Each language has its own unique costs. The size of these costs are dependent on context, be it a web business, or embedded environment.
The first component of this cost is runtime. C doesn't have a runtime, or rather it does but it is minimal, and comes for free in an Linux environment. Libc is often available for an application to link against. Other languages need the appropriate run time installed. I have found that as you move away from the popular platforms (e.g x86/64 Linux) finding a run time gets harder. Higher level languages need an operating system to support them. Some even need specific hardware. This make it especially hard to use these languages on a micro-controller.
The second component is the cost of updates. Libc is stable and the updates are few and far between. The stability of scripting languages varies. The interpreter is larger in size as well. A whole new python interpreter can be several tens of MB. In lots of embedded systems this is expensive. Many systems I work on are at the far end of a low bandwidth Internet connection, or are off line altogether. Larger updates present many problems. If an update is that expensive do you perform all updates? Or only the important ones? The latter means that the system will often be out of date. Most script based projects I have worked on are often smaller than an a similar C program. When factoring in the size of the runtime or interpreter the script is much larger.
The third component is control. High level languages trade control for power. Less control for more power and faster development. Python ships with its own web server, among other tools. This speeds up development at the cost of choice and control. These languages take you far away from the metal. Direct access to hardware is difficult. One way around this is a C wrapper library which can leverages the best of both worlds. I find C to offer greater control but usually when using few external libraries. Linux has a wide array of libraries available for development. Yet it is difficult to use them in an embedded environment. Each dependency will need to be recompiled for the target system. Mainstream packages tend to have better support for cross-compilation (especially for ARM) but your favorite open source library or application may not be set up for using alternate compilers. This tends to be all but impossible in non OS based systems such as micro-controllers.
Finally there is a question of the life expectancy of the system. In the web design world the average life expectancy in a project only appears to be a few years before it is replaced or retired. In the business and embedded world projects can last many years. I have worked on projects that were over a decade old, and one or two that reached their second. These long projects presents many interesting challenges. The digital world is not designed for long lived systems. How do you open a Word document created in 1998? As time goes on it becomes harder to find copies and download copies of the tool chain. When planning for a long support window it is best to use the Long Term Support (LTS) version of software. It is also important to have a copy of all dependencies and the source code as well. Embedded development is about control. It is important to control exactly what dependencies there are. In practice this means as few as possible.
There is a new generation of compiled languages that offer a better mix between power and control. Rust and Go are compiled languages that produce a single binary output. Cross platform and multi CPU support are available out of the box. It is thus easier to recompile an entire project and dependencies for a new system. They are still operating system dependent, making them unsuitable for bare metal devices. Their performance is beginning to rival C.
In Rust and Go the runtime bundled into application binary. Then it is a simple matter of copying the executable across to the target platform, from there it is ready to run. The only disadvantage of this is that this binary can be quite large. This may or may not be a problem depending on your circumstances. I have used Go in a few projects with great success and I look forward to finding an opportunity to use Rust.
Choosing a language for a project is not an easy manner, at least not in an embedded system. Often the choice is influenced by what is popular for the environment, e.g. JavaScript for web development, Java for business applications, C for the embedded world. Breaking the status quo will come at a cost. If these costs are understood and managed then the return on investment can be well worth the effort. In the embedded world, C is the current reigning champion. But there are more and more newcomers chipping away at its dominance. With Moore's law marching forward the costs diminish, making them ever more attractive.