Discussion: Context Dispatch - yes? no? questions? answers?

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” ?

2 Likes

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.

3 Likes

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)
1 Like

Hi, sorry, for reference here is the latest discussion we had on this.

1 Like

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.

2 Likes

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!

1 Like

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.

1 Like

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

2 Likes