Skip to content
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

Extend at-specialize to force specialization of arguments #33978

Open
rfourquet opened this issue Nov 29, 2019 · 7 comments
Open

Extend at-specialize to force specialization of arguments #33978

rfourquet opened this issue Nov 29, 2019 · 7 comments
Labels
domain:types and dispatch Types, subtyping and method dispatch

Comments

@rfourquet
Copy link
Member

A trick currently used in Base (and probably elsewhere) to force specialization on functions is to artificially declare a type parameter, e.g. foo(f::F) where F = f(1). I would bet that the majority of Julia users don't know about this and would look at this piece of code without any idea about the role of F, and would even fix what appears as a naive use of type parameters by simplifying it to foo(f) = f(1).
What about adding some explicit means to this end, for example reusing @specialize: foo(@specialize(f)) = f(1) ?
xref: #33917 (comment)

@rfourquet rfourquet added the domain:types and dispatch Types, subtyping and method dispatch label Nov 29, 2019
@cafaxo
Copy link
Contributor

cafaxo commented Nov 29, 2019

Since in foo(f::F) where F = f(1) the function f is called, it would be equivalent to foo(f) = f(1), right? Of course, for the other cases, it would be nice to have @specialize.

@rfourquet
Copy link
Member Author

rfourquet commented Nov 29, 2019

it would be equivalent to foo(f) = f(1), right?

I'm not the right person to answer, but this kind of prove the point that the exact rules are not obvious to everyone (talking of me!)

@cafaxo
Copy link
Contributor

cafaxo commented Nov 29, 2019

It is worth mentioning that #32817 added documentation on when a Function argument is specialized.
After thinking more about this, my opinion shifted somewhat: Having @specialize act in this way would not really clear up the confusion. The current syntax foo(f::F) where F is hacky, but so is overriding compiler heuristics. :)

@timholy
Copy link
Sponsor Member

timholy commented Nov 30, 2019

But I do think the intent of @specialize(f) is much more transparent than f::F ... where F. For a person with just enough knowledge of Julia to be dangerous 😈, the latter might induce him/her to "clean up" and remove that little annotation. And since we currently don't have tests for such specializations, and don't make performance regressions a "fail," we don't catch those kinds of changes.

@rfourquet
Copy link
Member Author

rfourquet commented Nov 30, 2019

It is worth mentioning that #32817 added documentation on when a Function argument is specialized.

Nice, I was wondering whether it was documented somewhere, but got too lazy to check. Otherwise I agree with Tim, the current way to force specialization is too easy to miss out, and is brittle. Overrriding compiler heuristics might be hacky, but we all love to do it :D And @inline gets its own explicit name.

If you think @specialize is not the right word to clear up the confusion, would another name do it? @force_specialize ?

@c42f
Copy link
Member

c42f commented Jun 25, 2020

I agree we need a way to do this.

In the last year I've noticed people start to use the static parameter trick more often, and each time I have to ask the question

"Is foo(x::T) where {T} an attempt to force specialization, or an ugly way to get at typeof(x)?"

Furthermore, we're then forced to leave a comment that this is indeed to force specialization, lest someone clean up the code later.

To make matters worse, the specialization heuristics are somewhat subtle (and presumably subject to change) so I've seen people start to throw this in at the first sign of trouble in the hope that it will help.

@c42f
Copy link
Member

c42f commented Jun 25, 2020

So looking at the code which processes @specialize, it seems that the per-argument form is currently ignored, ie the following doesn't actually do anything:

function foo(@specialize(x))
     body
end

See

julia/src/method.c

Lines 554 to 558 in 52c55d7

else if (nargs >= 1 && jl_exprarg(st, 0) == (jl_value_t*)specialize_sym) {
if (nargs == 1) // bare `@specialize` is special: it causes specialization on all args
m->nospecialize = 0;
st = jl_nothing;
}

So in principle we could steal @specialize(x) to mean "force specialize". However this form would be inconsistent with

function foo(x)
     @specialize
     body
end

which just resets the nospecialize flag for the method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
domain:types and dispatch Types, subtyping and method dispatch
Projects
None yet
Development

No branches or pull requests

4 participants