Beyond Foreign Function Interfaces
As a developer or as a software engineer, not reinventing the wheel is fundamental. This is usually accomplished by code reuse by importing libraries.
In this short article, I’d like to make the case for generalising the concept of a Foreign Function Interface (FFI).
1. Code re-use within a given language
Imagine you are working on Java project. You are likely to use a
dependencies manager such as maven
or gradle
.
Java and most newer languages actually benefit from a quasi-standard tool for handling dependencies (such as Rust with cargo, Javascript with npm, etc). Older languages, such as C or C++, tend to have no standard solution, or a multitude of partially working ones.
In Java, simply adding a dependency to your pom.xml
allows you
to quickly and effortlessly re-use any java libraries published on a central
repository such as maven central or
jcenter.
But what if a library you need has been written in a different language?
You could re-implement it, or you could use a FFI.
2. Foreign Function Interface (FFI)
Historically, many libraries were written in C, and developers of other languages wanted to use those. On the JVM the concept of FFIs was introduced early on.
A FFI is some glue code between a C API and the target language: here Java and the JVM. Once defined, java programs can use libraries with a C API at runtime.
This is great, but it has some drawbacks:
-
Other languages must define a C API, even though This glue code isn’t always straightforward to write;
-
The JVM will not handle the memory of the library, because no assumptions can be made as to how the library handles its memory. This also means that any memory leaks in the library’s code won’t be visible to the JVM for example.
The first drawback is inherent to having a common API language to be used as an FFI. The C API became a de facto standard. Some progress could be made by having a more flexible FFI language, but ultimately, no single API language can fit all programming languages.
3. FFI as dependencies?
Today’s software dependencies world is segmented:
-
Within a single language, other libraries are accessible with relative ease;
-
Calling a subset of other libraries can be done via FFIs, but those aren’t managed by the usual dependencies managers of the languages.
I strongly think FFIs and their associated libs should be handled by the same
dependencies managers we already use, such as maven
in Java.
4. Long term vision
As a software developer, I would like to see the following things happen someday:
-
every library of every language is delivered and uploaded to a single worldwide repository;
-
each language dependencies manager can use this common repository as a global source of artefacts (and maybe a unique manager could be used for any programming language);
-
FFIs are part of this.
Imagine being always able to use the best library for the job that was written in the best language for its domain!
Obviously, this will not be a simple journey, as some questions remain
regarding how to integrate widely different technologies together such as a
Nodejs
library called by some Rust
application binding it to an APL
and a
Fortran
code. Some technologies would simply be incompatible with each other.
5. Function As A Service (FAAS)
Interestingly, this concept is somewhat available at runtime with the proliferation of functions as a service.
This approach fixes the FFI question by replacing it by network communications and a specific message format, but this introduces latency for each call.
Increased latency is one of the all-in-the-cloud application evil twin.
6. Conclusion
Bright, you should hope the future is!