I want to present here again and perhaps more clearly, the concept of context dispatch , or more precisely resolving multiple dispatch based on some context.
I believe this can contribute to precompilation and load times issues, and may further the understanding of how to create a reusable binary cache for the compiled code and where and how to store such data.
The building blocks:
-
A Context is a set of modules.
-
The Context of module M is the set of all modules that module M depends upon.
-
Extension: for the purpose of multiple dispatch , a module M can declare that it extends function
fun
from module B. This in āJulianā terms is referred to as module M specifically imports functionfun
from module B. Any call toM.fun
will redirect toB.fun
andB.fun
itself will dispatch a to a specific method considering also the definitions ofB.fun
in its method table. -
Context Call: calling a function
fun
with a given context , the method table forfun
will be determined by the modules that are present in the context (and that extendfun
), the context is propagated recursively down the AST and every internal call is a context call.
There was previously some debate whether context call is feasible ā¦ I made some heroic attempts to prove so,
but @jrevels attempts were even more heroic, coming up with Cassette.jl which made my previous attempts redundant. kudos.
Binary Caching
Given a certain fixed context, it is quite clear that we can cache all compilation outputs for functions called within that context as long as we donāt define additional functions in any of the dependent modules.
It is also quite clear that the context of module Main
is not cacheable, since it is dynamic and changing from invocation to invocation.
The current state of affairs in Julia is that every call is equivalent to a context call with the context of Main. Which makes binary caching very hard if not impossible.
Possible solutions
All solutions should incorporate some heuristics for ānarrowingā the context, since any context that is not Main is probably cacheable.
-
Narrow context based on types, calling function
fun
from moduleM
with arguments types t1,t2ā¦
will narrow the context to the context of M if all types are instance-able from the context of M -
Post compilation narrowing: log the hierarchy of modules āvisitedā while compiling a function, log the compiled code in the smallest context that includes all visited modules. Then in a later stage if we encounter a function call from context M and there exist a binary cache for that function in M or in any of the modules inside Context of M ā¦ use the binary cache instead of compiling.
-
other?
Further discussion
I feel this is a complicated subject better addressed in small pieces.
using Cassette.jl I can easily set up a POC for any kind of context dispatch rules, I will do so if there is interest from the devs and community.