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

Enforce runtime-dispatch with atsign-invoke #35901

Closed
wants to merge 2 commits into from
Closed

Conversation

timholy
Copy link
Sponsor Member

@timholy timholy commented May 15, 2020

This is a tool to prevent invalidations due to partial specialization. For example,

!=(x, y) = @invoke !(x == y)

or, if you want to "manually union-split" known cases,

function !=(x, y)
    cmp = x == y
    isa(cmp, Bool) && return !cmp
    isa(cmp, Missing) && return !cmp
    return @invoke !cmp
end

This only affects cases where the types of x and y cannot be concretely inferred.

!=(x, y) = !(x == y)
```

and the compiler automatically specializes this for `x == y` returning either `Bool` or `Missing`:
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, this lovely type: Base.var"#64#65"{_A} where _A?

This is a tool to prevent invalidations due to partial specialization.
@vchuravy
Copy link
Member

Can you discuss the differences to invokelatest? The docs make it sound right now as if @invoke will force runtime dispatch, but as you mentioned at the end of the docs it doesn't impact the case where the types are concrete.

g(x) = x
f(x) = invoke(g, Tuple{typeof(x)}, x)
h(x) - Base.invokelatest(g, x)
julia> code_typed(f, (Int,))
1-element Array{Any,1}:
 CodeInfo(
1 ─     return x
) => Int64

julia> code_typed(f, (Integer,))
1-element Array{Any,1}:
 CodeInfo(
1 ─ %1 = Main.typeof(x)::Type{#s69} where #s69<:Integer
│   %2 = Core.apply_type(Main.Tuple, %1)::Type{#s65} where #s65<:Tuple
│   %3 = Main.invoke(Main.g, %2, x)::Any
└──      return %3
) => Any

@JeffBezanson
Copy link
Sponsor Member

I think we can do more automatically before encouraging a manual solution like this. If splitting certain call sites is a bad idea, we should just not do it (PR upcoming). From a programmer's perspective, I think it's quite hard to know where to use @invoke. I can imagine other annotations that might be easier, e.g. a @noinfer when you know the type of a certain call is not important. But mostly I think this one is on the compiler, and we simply must do inference and invalidations more efficiently.

@timholy
Copy link
Sponsor Member Author

timholy commented May 15, 2020

Would be awesome not to need this. I look forward to the PR.

Can you discuss the differences to invokelatest?

Main one is that this respects the world bounds.

@yuyichao
Copy link
Contributor

Seems that this is (ab)using the fact that invoke isn't well optimized in cases it could be. There could be a need for a invoke macro for calling invoke the function in a more convenient way. There may or may not be a need for a macro to discourage speculation from compilers but that should not be called @invoke.

@timholy
Copy link
Sponsor Member Author

timholy commented May 15, 2020

BTW, there are parts of this that may be useful, like count_instances makes it easy to check invalidations, and the enhancements to Base.visit are nice for making a more detailed analysis convenient. Should I split those out and submit them on their own?

@timholy
Copy link
Sponsor Member Author

timholy commented Dec 9, 2020

Not a lot of reason to keep this open, so closing.

@timholy timholy closed this Dec 9, 2020
@timholy timholy deleted the teh/atsign_invoke branch December 9, 2020 15:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants