The Julia module Polyglot.jl supports transparent remote/recursive evaluation between Julia and another interpreter through automatic call serialization.
In poorer words, Polyglot.jl lets you call functions in other languages as they were regular Julia functions. It also allows other languages to call Julia functions as if they were native.
Remote output is also transparently redirected locally, and since the evaluation is performed through a persistent co-process, you can actually spawn interpreters on different hosts through "ssh" efficiently.
Polyglot.jl is currently a work-in-progress. Suggestions about API design are highly appreciated: we're looking for a consistent calling interface between regular Julia's multiprocessing and other external language bridges.
As an additional note, while Polyglot.jl can be used with Python, it's definitely not as sophisticated or as efficient as PyCall. If you don't need to run multiple/remote/mixed Python instances (for example, to mix major Python versions or to use PyPy), using PyCall is advisable.
Polyglot.jl can communicate with another interpreter by "bonding" with it:
Bonds can be constructed by using the bond!() function:
You can override the default interpreter command using the second argument, which allows to specify any regular command to be executed:
An additional list of arguments to the interpreter can be provided using the third argument, args:
The optional arguments are just strings. They are quoted and appended to the main command after default arguments.
Default arguments may be supplied automatically by the driver to force an interactive shell; for example "-i" is supplied if Python is requested. You can disable default arguments by using def_args=False.
The following keyword arguments are supported:
Working directory for the interpreter (defaults to current working directory).
Environment for the interpreter (defaults to ENV).
Enable (default) or suppress default, extra command-line arguments to the interpreter.
Defines the timeout for the underlying communication protocol. Note that bond!() cannot distinguish between a slow call or noise generated while the interpreter is set up. Defaults to 60 seconds.
Enables/disables "transparent exceptions". Exceptions are always first class, but when trans_except is enabled, the exception objects themselves will be forwarded across the bond. If trans_except is disabled (the default for all languages except Julia), then local exceptions will always contain a string representation of the remote exception instead, which avoids serialization errors.
reval(bond, code; block=false)
With block=false (the default), evaluate and return the value of a single statement of code in the top-level of the interpreter.
With block=true instead, evaluate a code block in the top-level of the interpreter. Any construct which is legal by the current interpreter is allowed. Nothing is returned.
Return a reference to an single, unevaluated statement of code, which can be later used in reval() or as an immediate argument to rcall(). See Quoted expressions.
Terminate the communication with the interpreter.
rcall(bond, name, args...):
Call a function "name" in the interpreter using the supplied list of arguments *args (apply *args to a callable statement defined by "name"). The arguments are automatically converted to their other language's counterpart. The return value is captured and converted back to Julia as well.
Return a function that calls "name":
exportfn(bond, func, name):
Export a local function "func" so that can be called on the remote language as "name". If "name" is not specified, use the local function name directly. Note that "func" must be a local function, not a function name.
proxyfn(bond, name, other_bond, other_name):
Export a remote function "name" from "bond" to "other_bond", named as "other_name". If "other_name" is not provided, the same value as "name" is used:
Start an interactive session with the underlying interpreter.
Beware that both BondSerializationException (with remote==true) and BondRemoteException may actually be originating from uncaught local exceptions when an exported function is called. Pay attention to the error text/data in these cases, as it will contain several nested exceptions.
Polyglot.jl has minimal support for working with quoted expressions, through the use of rref(). rref() returns a reference to a unevaluated statement that can be fed back to reval() or as an immediate (i.e.: not nested) argument to rcall(). References are bound to the interpreter that created them.
rref() allows to "call" methods that take remote un-serializable arguments, such as file descriptors, without the use of a support function and/or eval:
Since references cannot be nested, there are still cases where it might be necessary to use a support function. To demonstrate, we rewrite the above example without quoted expressions, while still allowing an argument ("Hello world!") to be local:
Or more succinctly:
If you are interested in announcements and development discussions about Polyglot.jl, you can subscribe to the bond-devel mailing list by sending an empty email to <email@example.com>.
You can contact the main author directly at <firstname.lastname@example.org>, though using the general list is encouraged.
9 months ago