But it’s easily defeated; after you’ve triggered the invalidations and collected the data, just set it back again. And the fact that invalidations is empty is a dead giveaway.
But of course, this deserves gobs of “devilishness” points! I’m impressed by all the impishness here.
Idea was to prevent another form of fiendish cheating: anyone building from source might just greatly expand the list of things we precompile in contrib/generate_precompiles.jl and then get a much bigger, juicier set of targets that haven’t been spruced up as much as the stuff we’ve been shipping precompiled.
Turns out the BitInteger union is not needed. I was starting to feel that using Union Types might even have to become its own category, as I was building larger and larger ones to get more invalidations with a single method. But this is just as effective with convert:
julia> using SnoopCompileCore
julia> invalidations = @snoopr Base.convert(::Type{T}, x::Number) where T<:Real = T(x);
julia> using SnoopCompile
julia> length(uinvalidated(invalidations))
18362
Redefining @nospecialize to actually specialize.
I thought this should invalidate a bunch of things that otherwise wouldn’t be invalidatable, but seems not to have.
MIght have missed something
julia> inv = @snoopr Base.@eval macro nospecialize(x)
x
end
Any[]
julia> length(uinvalidated(inv))
0
Redefining a macro doesn’t have any effect on already-evaluated uses of the macro—the current meaning of the macro is used at parse time and after that there’s no connection. I’m pretty sure that’s how all macro systems work. Otherwise it would be like trying to go back and fix the results of past calls to functions when you redefine them.
If these macros called some auxiliary inner function (inside the methods they modify) that could be invalidated, then this could work. But I do not know if it is the case (would guess no).
Just to clarify, I meant something like: @my_macro args expands to my_aux_f(args...) inside the method body of a function outer, so changing function my_aux_f (not macro my_macro) could invalidate the method outer. Having a programmer write the call to my_aux_f and a macro to do the same has indistinguishable results no?
For a concrete example, if I somehow change print, and @show is expanded to print, then every method calling @show may be invalidated, no?
Yikes, realized I forgot to announce the results on Friday. To evaluate the submissions, I tested each using a script that I executed from the linux prompt to ensure there weren’t differences in my typing at the REPL (since hitting certain keys can force the compilation of new methods). In a couple of cases, this led to a pretty different count than provided by the submitter, perhaps mostly because some REPL methods did not compile. (At least the rank order was consistent with the numbers provided by the applicants.)
Without further ado, here are the results of my analysis and the winners…
For the category of “pirating methods,” we had several submissions including a nail-biter for the win:
third place variants of overloading +:
the original submission was Base.:+(x::Int, y::Int) = Base.inferencebarrier(Base.add_int(x, y)) (the inferencebarrier isn’t required ) by @simeonschaub at 15782
an improved/more evil version Base.:+(x::T, y::T) where {T<:Base.BitInteger} = Base.add_int(x, y) by @StefanKarpinski at 15933
second place: Base.getproperty(x, s::Symbol) = getfield(x, s) by @simonbyrne at 17035
first placeBase.convert(::Type{T}, x::Number) where T<:Real = T(x) by @tomerarnon at 17093
In the non-pirating category, we had:
second placestruct DoNotCare<:Real end; Base.:(==)(x::DoNotCare, ::Any) = true by @oxinabox at 58
convert methods:
struct X end; Base.convert(::Any, ::X) = nothing by @oxinabox at 1666 was disqualified (sorry) because to be a valid convert method it should have been Base.convert(::Type{Any}, ::X) (which has 1152 and would have won), so the winner is…
first placestruct X end; Base.convert(::Union{}, ::X) = nothing by @mbauman at 903
In case you’re curious, in the non-pirating category I believe that it’s not currently possible to do better than the following rather arcane submission:
struct X end
Base._str_sizehint(::X) = nothing
at 2622 invalidations. You can discover this and similar opportunities by installing MethodAnalysis and then running demos/abstract.jl and typing mipriv on the command line. (mipriv means “MethodInstances of private, a.k.a. non-exported, names”; the analog for exported names is miexp).
Congrats to the winners, and let the second phase commence! Announcement will likely be made on Saturday as I am reserving Friday afternoon for a family bike trip.
I’ld like to appeal. convert(::Any, ::X) isn’t against the rules.
It’s not piracy since X is my own type, and i see no special rule for convert .
It’s not sensible julia code, but that wasn’t a requirement.
I think the only vaguely sensible things submitted were my DoNotCare one and the MyCustomString one at the start.
…and the appeal is upheld! We have a new winner, @oxinabox
I realized the same remark could apply to the second: that the way convert is intended, it should probably be convert(::Type{Union{}}, ::X). So either way, @oxinabox wins.