-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Decouple dispatch and specialization #11339
Comments
Would this potentially require type parameters to be mandatory for good performance in many more situations than they are now? I worry whether this would make Julia's performance characteristics even more complicated to understand for new users. Or maybe this would somehow end up becoming more intuitive in the end? Not sure. (Is this what you meant by "performance could get finicky"?) |
Yes, that was my concern. I edited the rules above so that I think we could maintain julia's current behavior but add new ones. |
I think specialization has to be a property of functions, not the type itself. The better version of this is to automatically figure out which parameters the function doesn't depend on, and avoid specializing on those (in other words, discover "parametricity" in the technical sense). |
I just spent a lovely hour+ re-reading JuliaLang/LinearAlgebra.jl#42. What bliss. Surprisingly, I found myself back this issue, which I'd forgotten about entirely. I think @JeffBezanson's comment above is potentially important, and I'm just checking two things:
For the latter, consider a simple example: function fill!{T}(A::AbstractArray{T}, val)
valT = convert(T, val)
for i in eachindex(A)
A[i] = valT
end
A
end For all In other words, for those of us not working on the compiler, is this worth being concerned about as we contemplate different paths forward? I'm guessing the answer is no, but it would be interesting to hear reflections on this. My reasoning is that presumably this has to be solved not at the level of the method, but at the level of individual cached (compiled) instantiations. In that case one can specialize for certain types of inputs but use more general code for others, and that solves the problem I'm worrying about above. |
Thinking just a little bit more: presumably the ideal way to implement this corresponds to generating a method for |
I think a good item for 1.0 here is to deprecate |
Would |
Eventually, yes. |
I'd have to say, this would be pretty amazing, to have in-built static arrays like this. We'd need non-resizable One problem to solve is that you'd only ever want to dispatch to a static-sized method if the size typevar was known to the compiler. To avoid dynamic dispatch, you'd need another annotation on methods so that the method is only considered when inference can infer the relevant information. The annotation would imply a promise to the compiler that the method is functionally identical to the one it specializes, or else we'd have determinism problems. We'd also need to store such abstract types unboxed, for performance. This could solve a range of problems, such as a |
1.0 part of this is done. |
This would be very useful for shape checking ML programs, where runtime shape errors are notoriously vexing. See this: aviatesk/JET.jl#82 (comment) for an example where it "just works" with JET.jl and sized arrays, but again compilation cost is an issue. Would also be helpful for IPO Escape analysis, which according to the docs would do better with propagating array shape info. And This issue here: #43642 Is it possible to have this be opt in so as to not be a breaking change and be available during 1.x? |
|
Is it possible to specialize on just specific type parameters? Edit: What if I want to include the whole shape of an array but specialize only on the rank and element type I'm not sure if that even makes sense in principle though. |
I don't think this should be closed since there could still be much more control over what to specialize on. |
aka "Generalize the ANY mechanism" aka "Completely destroy Jeff's life forever"
(continuing the heresy in JuliaLang/LinearAlgebra.jl#42 in a direction that might be more profitable, but much harder)
What if we could encode an Array's size among its type parameters, but not pay the compilation price of generating specialized code for each different size?
Here's a candidate set of rules (EDITED):
type Bar{T,K*}
means that, by default, functions are specialized onT
but not onK
. Array might be defined astype Array{T,N,SZ*<:NTuple{N,Int}}
(in a future world of triangular dispatch).foo(A::Array)
specializes the element type and the dimensionality, but not the size.foo{T,K}(b::Bar{T,K})
would specialize onK
, for example. Conversely, putting * after a type parameter causes the parameter to be used in dispatch (subtying and intersection) but prevents specialization. This is much like the ANY hack now.matmul{S,T,m*,k*,n*}(A::Array{S,2,(m,k)}, B::Array{T,2,(k,n)}
would perform the size check at compile time but not specialize on those arguments.I'm aware that this is more than a little crazy and has some serious downsides (among others, it feels like performance could get finicky). But to go even further out on a limb, one might additionally have
matmul{S,T,m<=4,k<=4,n<=4}(...)
to generate specialized algorithms (note the absence of *s) for small sizes and use the unspecialized fallbacks for larger sizes. This way one wouldn't need a specializedFixedSizeArray
type, and could just implement such algorithms onArray
.A major downside to this proposal is that calls in functions that lack complete specialization might have to be expanded like this:
The text was updated successfully, but these errors were encountered: