Best way to handle language interoperability

%fcompilerinteroperabilitylanguage-designprogramming-languages

Background

In a language like F#, direct interoperability with most other .NET languages is possible. For example, it is possible to use classes written in C# directly in F#, and it is possible to call F# code directly from C#.

In F#, modules are compiled to CIL instructions corresponding to static classes, ADTs to a class hierarchy (abstract class + subclasses) and so on. This makes interoperability easy, but puts some limitations on language features.

For example, F# does not support higher-order modules like OCaml and SML does (or a 'similar' mechanism such as typeclasses or the like). Whether this is crucial or not is subjective, but it does limit the options to write polymorphic code (without using the OO parts of the language).

Interoperability through some interface

Of course, an alternative is not ignore the interoperability concerns in the main part of the language, and make some specific interoperability-interface. This could be one-way or two-way.

For example, in a language like F#, an alternative design could have been something like:

  • Let F# use C# classes directly, such as today. In this way, using .NET libraries is still easy.
  • Ignore C#'s ability to access functional F# code directly. This would remove some limitations that are currently imposed on the language design – we could in this way easily support a stronger type system, with higher-order modules or typeclasses, etc.
  • Let C# access the OO parts of F# directly. Hence, if you want to let our F# libraries be accessible from C#, we would have to put them in a thin'ish OO wrapper.

This would require a bit more work in some cases, but in my experience I would probably expect that most people would design an OO wrapper anyway, if an F# library is to be used in C#.

In case an F# library doesn't have an OO wrapper, it would still be possible to make one yourself (in F# obviously).

In the more extreme case, this interface could be two-way, such that F# could only access .NET classes through some interface as well – but there would probably be little reason to impose such restriction in this case. But for other languages, it might be an option – if for example, you wanted to write a pure language or something like that.

The actual question: Pros and cons

  • What are the pros and cons of each of these approaches?
  • Would it be technically unfeasible or impractical?
  • Would it be impossible for C# to interoperate with an assembly that is "misusing" the CLR or anything like that? (note, the question is not .NET specific, and you might as well base your answer on JVM langs like Scala, or whatever you know best)
  • Are there any languages which have used the inferfaced approach on? (on a higher level like .NET to .NET, and not just languages having an FFI to low-level code or the like)

Best Answer

One of the issues is programming to a model. The other issue is programming to a machine. So you can program to a model and create an intermediate compilation that maintains any kind of special feature. The intermediate then needs to be something that programs a machine. There can be extra code given support libraries that provide compatibility for expanding the machines understanding or to downgrade what the code executes.

Ignoring functional code from C# does not improve F#. F# is currently modelling in a similar style as Ocaml (but for a .Net ecosystem) with enhancements and it is more a situation of F# working with the runtime and type system. If you expand what can be expressed by that runtime, every language can benefit.

Since delegates are designed like one method classes that are used to embody units of execution, things like lambda functions in C# are already thinly wrapped. F# does a similar thing with modules as classes with static methods. This is all for free.


It is not unfeasible to cut off one language from another. It is impractical to make languages harder to interoperate. The reasons are many goals are to extend and improve the runtime to allow more languages and to encourage cross library usage. Of particular with C#, it is not limited in what library it can call if it can consume an exposed and sensible values to its type system. The code can be unsafe and can be marked as such. It could (possibly by some future feature) mark code as advanced to allow it to do more that can be done in IL.

The problem managing the codebase for the checks to support the extra features in the compiler and the generators is to flesh out some useful code patterns found. So if you are generic in type, then the compiler would generate versions for every type of every kind that is a resolvable possibility or a lazy jitting generator base on use. Then you will think about what assures a kind is considered? Is it only a table lookup for usages or included scopes?

The easy out answer is time and desire. As outside influence voices its various opinions on matters and time allots itself to those issues, it comes to the attention of primary authors to consider the options. The usersvoice site helps. I myself have interest is in hygienic macros to expand beyond what and how I write code. Thank you. Good day.

Related Topic