6.9 KiB
layout | title | category | tags | order | |||
---|---|---|---|---|---|---|---|
developer-doc | Polyglot Bindings | polyglot |
|
1 |
Polyglot Bindings
This document deals with the specification and design for the polyglot interop system provided in the Enso runtime. This system allows users to connect Enso to other supported programming languages, to both provide access to a wealth of libraries, and to integrate Enso into existing systems.
The polyglot support in Enso is best-in class, and it supports this through two main mechanisms:
- Polyglot FFI: The low-level polyglot support provides a fairly low-level syntax sugar system for working with values from foreign languages.
- Embedded Syntax: This system allows users to write code from other
languages directly in their
.enso
files, and to seamlessly share values between Enso and that foreign code.
Impedance Mismatch
Polyglot interoperation in Enso has a significant impedance mismatch. In essence, this means that there is a mismatch between Enso's language semantics and the semantics of the foreign languages that are being worked with.
While some of this mismatch can be worked around by manually wrapping the foreign constructs in Enso, there are still concepts that can't easily be represented by Enso.
The actionables for this section are:
- Expand on the impedance mismatch and how it leads to the defined semantics.
The Polyglot FFI
The low-level polyglot FFI mechanism refers to a way to use polyglot objects directly in Enso code. This can be used to underlie a library implementaion in Enso, or to interoperate with code running in other languages.
The mechanism provides users with the facilities to import bindings from other languages and call them via a generic mechanism.
Importing Polyglot Bindings
When importing a polyglot binding into scope in an Enso file, this introduces a polyglot object into scope. This object will have appropriate fields and/or methods defined on it, as described by the foreign language implementation.
The actionables for this section are:
- Expand greatly on the detail of this as the semantics of the imports become clearer.
Using Polyglot Bindings
With a polyglot object in scope, the user is free to call methods on it directly. These polyglot objects are inherently dynamically typed, meaning that any operation may fail at runtime.
Enso implements a generic variadic syntax for calling polyglot functions using vectors of arguments. In essence, this is necessary due to the significant impedance mismatch between Enso's runtime semantics (let alone the type system) and the runtime semantics of many of the polyglot languages.
We went the way of the variadic call for multiple reasons:
- It allows us to match up with a wide range of language semantics (such as subtyping and overloading).
- It is flexible and easy to expand in the future.
- We can easily build a more Enso-feeling interface on top of it.
By way of illustrative example, Java supports method overloading and subtyping, two things which have no real equivalent in the Enso type system.
The actionables for this section are:
- Expand greatly on the runtime semantics of working with polyglot bindings.
- Determine how to make the inherent 'failability' of polyglot objects safer.
Importing Polyglot Bindings (Syntax)
Polyglot bindings can be imported using a polyglot import directive. This is constructed as follows:
- The
polyglot
keyword - A language identifier (e.g.
java
). - The keyword
import
. - Optionally (where the language supports it), an identifier for the type of
language entity being imported (e.g.
struct
forc
). - A path that uniquely identifies the polyglot object to import.
- Optionally, the keyword
as
, followed by a new name.
For example:
polyglot java import org.example.MyClass as MyClassJava
polyglot c import struct NetworkPacket as NetworkPacketC
Using Polyglot Bindings (Syntax)
A polyglot binding is a polyglot object that has methods and/or fields defined on it. Due to an impedance mismatch between languages, Enso implements a variadic syntax for calling these polyglot bindings using vectors.
In essence, we have a primitive function as follows:
Polyglot.method : Polyglot.Object -> [Any] -> Any
It works as follows:
- It is a method called
method
defined on thePolyglot
type. The namemethod
is, however, a stand-in for the name of the method in question. - It takes an object instance of the polyglot object.
- It takes a vector of arguments (and is hence variadic).
- And it returns some value.
By way of example, the following is a valid usage of a polyglot binding:
polyglot java import com.example.MyClass as MyClassJava
main =
x = MyClassJava.foo [1, 2, 3] # a static method
inst = MyClassJava.new [a, b, c] # a constructor
bar = inst.metod [x, y] # a static method
Finding Polyglot Bindings
Polyglot objects for various languages are found in the polyglot
subdirectory
of an Enso project. This folder is subdivided into directories based on the
polyglot language. The name of each subdirectory must match the language
identifier used in the source code.
Inside each directory is an implementation-defined structure, with the polyglot implementation for that particular language needing to specify it. Please see the language-specific documentation for details.
Embedded Syntax
The term "Embedded Syntax" is our terminology for the ability to use foreign
language syntaxes directly from inside .enso
files. This system builds upon
the more generic mechanisms used by the polyglot FFI to
provide a truly seamless user experience.
Embedded Syntax Usage (Syntax)
A polyglot block is introduced as follows:
- The
foreign
keyword starts a block. - This must be followed by a language identifier (e.g.
python
). - After the language identifier, the remaining syntax behaves like it is an Enso
function definition until the
=
. - After the
=
, the user may write their foreign code as a string.
foreign python concat a b = """
def concat(a, b):
str(a) + str(b)
In the above example, this defines a function concat
that takes two arguments
a
and b
, implemented in Python.
The actionables for this section are:
- Greatly flesh out the syntax for the high-level polyglot functionality.