I wonder what the devs and community think of the direction of context dispatch as it has been recently presented in other various posts.
What do you mean by âcontext dispatchâ ?
It would be great if you could at least link the relevant posts, or ideally write up a coherent, detailed proposal. Reviewing something scattered over âvarious postsâ is not ideal.
If you meant âcontextual dispatchâ, this is what allows you to override existing functions in the context of GPU processing. So it has its applications.
@context GPU
@contextual(GPU) sin(x::Float32) =
ccall((:__nv_sinf, :libdevice), Cfloat, (Cfloat,) x)
Hi, sorry, for reference here is the latest discussion we had on this.
The answer should be yes, or in some case you cannot extension things at all.
If you re-extension some already existing methods, you do type piracy. However, something to achieve the functionalities(of new extension for some argument type) might be a hard demand, which comes up with a requirement about scoped method dispatch aka an instance of the contextual dispatch.
If youâre referring to the ability to âsafelyâ add dispatches that would normally be considered type piracy, then the widely-understood âcontextual dispatchâ (aka Cassette or IRTools) is exactly what you want. The real issue with regular type piracy is that it can cause unexpected behavior by just loading a package; if such a change in behavior instead required a call to Cassette.overdub
to occur, then it wouldnât be type piracy at all (at least not in the detrimental sense).
In other words, we already have this and it works quite well!
Would you mind briefly reiterating what your form of âcontextual dispatchâ implies? The sharing of this term with what Cassette-like packages implement makes things rather confusing (maybe you can come up with an alternative term for it?). Some things Iâd like to have explicitly stated include:
- How it differs from the equivalent term used to describe how Cassette et. al work, i.e. âoverdubbingâ or âuser-defined passesâ.
- What problems itâs intended to solve that arenât already solved well via a different approach (such as with Cassette).
- What will be required to implement it, and where it will need to be implemented (can it be done in a package, or do the changes need to be to Juliaâs core?).
- Has anything changed w.r.t your âcontextual dispatchâ in the months since your original post? EDIT: Hereâs the post Iâm referring to: MultiFunctions: Context dispatch and binary cache
It is very similar to âContext Dispatchâ of cassette but is aimed to be implemented on the language level.
It would help solve a few current pain points of the language.
This seems like it requires a new version of sort!
to be compiled not only for each type signature (roughly what we currently do), but also for each type signature and for each calling context since the method tables of all functions that are called are different in different contexts. This seems like it would massively increase the amount of compilation required, not decrease it.
What if module A
instead defined
isless(x, y) = "surprise!"
This seems like it would cause sort!
to fail with a method error even though the two isless
functions are not the same generic function and Base is not trying to call the one that A
defines or exports.
That is generally correct unless some heuristic is inserted for narrowing the contexts, however, even in the general un-optimized case, all of the compilation output is cachable and reusable.
Whereas currently in every Julia session sort!
is being compiled again and again.
So overall Context Dispatch even in its space wasting general form, would still decrease the amount spent on compiling drastically.
Ah, very interesting, that is not directly relevant to Context Dispatch but to the complementary idea -Automatic Merging of Exported Functions.
And in that case you should get a Method Error: ambiguous just like you would get now.
for example in the following code:
struct A
a::Int
end
Base.isless(x,y::Main.A) = Base.isless(x.a,y.a)
Base.isless(x::Main.A,y) = !Base.isless(x.a,y.a)
vecA = [A(1) for i=1:100]
sorted = sort(vecA) #MethodError: isless(::A, ::A) is ambiguous.
This is an issue that was already discussed before, in terms of the SharedFunctions
discussion
A different generic function with the same name is a function with the same name as another function⌠For example:
module A f(x) = x end module B f(x, y) = x + y end
Here
A.f
andB.f
are different (generic) functions.The reason why we cannot just merge the two
f
is because of how you write generic code.
How about this rule to solve this: Only import a name from a SharedFunctions package if you donât intend to write generic method with only the Any type dispatch; otherwise have the generic definitions in SharedFunctions Shared function names with completely generic method definitions should either have the generic definitions in the SharedFunctions package not be imported from SharedFunctions This way, if there is a need for generic methods, the fully generic method is either shared by alâŚ
In theory we could almost make it automatic, right? That is, have a github bot that generates a PR that extracts all exported function names, abstract types and abstract docstrings into an abstract header package, and rewires the old package to require and import and extend and reexport functions from the abstract header package. In theory, the creation of lightweight AbstractFoo / HeaderFoo packages from some Foo package should not requite a lot of human thought or intervention (corner case: âŚ