Description
I think the greatest thing about PythonCall/JuliaCall is how easy it makes it to integrate Julia into a Python project, so that one can gradually port the hot inner loops into Julia functions. I think it could be made even easier to do this, and wanted to share a couple of ideas.
1. Julia should be optional
Installing Julia on every user’s machine is a big ask for heavily-used Python libraries that have battle-tested build scripts. Therefore I think the process of Julia-izing a Python library should be very gradual, and allow for a Julia backend to be optional.
I think it would be nice if there was a standardized and documented way to check for the availability of juliacall
without triggering an install of Julia, which would open up specific high-performance branches of code. For example,
if juliapkg.is_installed():
# Julia branch of code
else:
# regular code
In a package, you could create an optional “extra” set of dependencies which would install the juliacall library and also trigger the juliapkg.is_installed
branches to become True
.
I think this may be preferable in some cases to simply checking the presence of juliacall
in the user’s environment which might be installed from another package. For this idea, the user would need to explicitly install the Julia backend with something like
pip install "mypackage[julia]"
For those checks to trigger.
Thus, if a package developer chooses to make this an option, users would need to opt-in to enable the faster behavior.
2. Syntax for Julia versions of functions
In a similar direction, I wonder if there is another syntax available for writing Julia versions of functions. One idea is to have something like @numba.jit
, but with a Julia version, which could look like
@juliacall.pydef
def foo(x):
return np.sum(x ** 2)
@juliacall.jldef(foo)
def foo_jl(x)
return """
x -> sum(xi -> xi^2, x)
"""
The jldef
would run juliacall.seval
on the return value of the Python code (a string), and feed the arguments of the function to the resulting anonymous function. This would be cached.
In addition, the jldef
version would only be activated if a user installs the Julia backend of the package. The pydef
version would check if it is installed, and call the Julia branch of the code, which gets associated using the jldef(foo)
specification.