Are there other possible reasons for invalidation, or is there just a lot of type-unstable code out there?
Piracy can cause invalidation, and indeed checking invalidations seems to be one of the better ways of detecting piracy you may not have known about. But in my experience most invalidations are triggered by poor inference. Sometimes that’s not surprising; there are good reasons that Pkg uses Dict{String,Any} for a lot of stuff, but it turns out that if you don’t want Pkg’s code to be invalidated you then later have to annotate some objects whose types you happen to know.
Also, an earlier effort to reduce latency was to skip inference on various functions to avoid specializing when it wasn’t necessary (with
@nospecialize). Wouldn’t this make the invalidation problem worse by making more methods susceptible to being invalidated?
Exactly right. Adding @nospecialize is often an extremely good idea for reducing latency, but what I’ve learned more recently is then you sometimes might want to make some adjustments by adding “safe” type annotations in places where it matters. That is, if you’re calling somemethod(i::Integer), and you’ve added @nospecialize annotations that prevent inference from knowing the exact type of i but you happen to know it’s really i::Int, you might want to write that call as somemethod(i::Int) (not in the signature of the method, but in the body of the caller).