-
-
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
incremental precompile warning turned into error: breaking? #52213
Comments
Does he? It seems to me he's saying something is actually "fatally broken"? I.e. not good for the ecosystem if you change a method from another package (maybe not fatal in itself, until the ecosystem grow more, or more packages composed), but depending on the order of how you do it, for different packages trying to modify the same, is "broken". I suppose if you do redefine in a certain order it COULD be ok, if you're ok with that, and the order is correct, something you're ok with. And changing this to an ERROR is then a breaking change. But I'm not sure most users are ok with this, or know the issue? E.g. in his example if only B or C is used, then ok, but would users for sure test the ecosystem for B AND C, or the other order C AND B, and would be ok with both the different conclusion? Must not either be wrong, and you might even have a combinatorial explosion of possible orders, and only 1 (or few?) ok. I suppose it best to let this error. It seems to me the WARNING SHOULD have been a sign you or the ecosystem needed to change, and now the ERROR is forcing it. You always have the option of using the older Julia version where this "worked" in some sense, maybe with wrong answer?! or I mean at least not what you though would happen? |
Warnings are printed when something should not be relied upon working, as it is known to be broken. Ignoring warnings is buyer-beware. But it was pointed out that this lacks a NEWS entry, since changing warning to error usually doesn't seem to merit one, but it might in this case Also worth pointing out in that NEWS that this is only a problem if you want to incrementally compile code. If you avoid using |
Yes, surely:
|
As a user, I typically don't care how the code is compiled. So, how to tell Julia that I don't explicitly want "incremental" compilation for installed packages that throw this error? |
This is quite an unusual take on warnings, IMO. Does this mean that deprecated functions can just be removed in the next minor Julia version? |
He does write:
So if you don't, nor your packages, then you're ok... yes, it's not unheard of in the ecosystem, but it IS bad?! He's saying any order will compile to something, but not the same thing. So it's deterministic, and COULD be allowed. I'm just not sure most users realize. When I have e.g. a Python package, implemented in C, I think I can import them in any order, and all will work the same, since there's no possibility of the C code being changed after/when importing. For Python code, or the wrapper code of that C code, that might actually not be true, since Python is very dynamic. Though I'm not sure. Is there some good non-breaking way out of this? I'm also thinking, one package may need a certain version, e.g. latest, and another might not be able to use that version, so preventing installing two packages at the same time. Might we want to allow that different packages can depend on the same package, just different versions? If we allow that, then we make this headache even more complex, OS should people be able to change and get new versions, and all valid? It might still be a warning if you do something such unusual... |
Well, showing a warning "the state of your packages may depend on the loading order" is totally fine, and would be much easier to understand than the current warning text. Note that this warning doesn't imply that there's order dependency, it's just a possibility. |
If warnings have been present in all minor releases, yes, since there hasn't been a version in which it was part of the API. Otherwise, semver says it would be a major version change. The workaround is |
I concur with @aplavin - it may make sense to prevent a package developer from doing this going forward, but it doesn't make sense to prevent an end user from relying on an already existing package/version from being able to use that package going forward. From both perspectives, I never knew what the error actually meant, what impact I was really being warned about. Everything seemed to work fine. What specifically was broken that I might care about? I couldn't tell you. I would highly recommend first making the meaning of the warning more clear before taking a further step. And when that next step is taken, it should make sure that older packages don't need to be updated to continue to be used on future Julia versions. Maybe it's just added as a check for new General registrations. Maybe there's a switch for an end user to turn off. |
What might happen is that it might segfault occasionally, which is what it started doing very often when we decided to change the warning to an error |
Where do I put this as a user, without changing loaded packages code? |
On a more general note, I consider myself pretty familiar with Julia and packages, and this is the first time I heard this perspective on warnings. I think going forwards this is important to highlight wherever semver/compatibility is promised, that as soon as you see any warnings – no backwards compatibility for you! I doubt many people realize this. |
We shouldn't warn (or error) where there's no actual problem. It seems to me (incremental) compilation is a red herring. It's the redefinition that's the problem?! This would also be a problem with the interpreter, or without precompilation? At some point you must compile (or interpret) and if you precompile, then potentially you recompile. The only way out of that is not allowing redefinition, i.e. type piracy? But it's also very useful in an interactive system if you know what you're doing... or annoying if you couldn't redefine e.g. functions or structs... It seems there will always be a tension, and that for packages you may want to disallow more changes.
You mean get similar to what C packages in Python give you? They are not generic. I think we could disallow recompilation for existing types (like there), but allow adding new types, and they would work with those packages, note that's addition (and implied compiled code), not a change, thus not type piracy, still more compilation. Recompilation would be the wrong word for that. |
Ok, I guess putting concrete examples here would help. They are in the slack thread, but not here.
In both cases, potential order dependency is not an actual issue at all. |
You can do the method overwrite in |
I'm not arguing with this at all, just please let me know if there's any workaround on the user side (without changing package code). This would greatly help dealing with the breakage. |
Actually, looking at it again – why is the policy different for different warnings? The incremental compilation one doesn't appear in earlier 1.x versions: ❯ cat M/src/M.jl
module M
Base.:+(::Bool, ::Bool) = 1
end
❯ rm -rf ~/.julia/compiled/v1.6
❯ julia +1.6 --project=M
┌ Warning: Couldn't load Revise
└ @ Main ~/.julia/config/startup.jl:12
_
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.6.7 (2022-07-19)
_/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release
|__/ |
(M) pkg> precompile
Precompiling project...
1 dependency successfully precompiled in 2 seconds
julia> using M or (@v1.6) pkg> activate --temp
Activating new environment at `/var/folders/2j/9vtd991d201dbkh9dnx3wvy00000gq/T/jl_YAInvl/Project.toml`
(jl_YAInvl) pkg> add ConstructionBaseExtras
Resolving package versions...
Updating `/private/var/folders/2j/9vtd991d201dbkh9dnx3wvy00000gq/T/jl_YAInvl/Project.toml`
[914cd950] + ConstructionBaseExtras v0.1.1
Updating `/private/var/folders/2j/9vtd991d201dbkh9dnx3wvy00000gq/T/jl_YAInvl/Manifest.toml`
[187b0558] + ConstructionBase v1.5.4
[914cd950] + ConstructionBaseExtras v0.1.1
[8197267c] + IntervalSets v0.7.8
[1e83bf80] + StaticArraysCore v1.4.2
[ade2ca70] + Dates
[8f399da3] + Libdl
[37e2e46d] + LinearAlgebra
[de0858da] + Printf
[9a3f8284] + Random
[9e88b42a] + Serialization
[2f01184e] + SparseArrays
[10745b16] + Statistics
[4ec0a83e] + Unicode
Precompiling project...
4 dependencies successfully precompiled in 3 seconds
julia> using ConstructionBaseExtras Also, reverted title to a correct one again: the main question asked and discussed here is not whether NEWS entry is needed, but whether this change is breaking. Better to have title and content consistent... |
I think that is because |
I think |
So in this scenario the user-facing behavior is: no warnings, perfectly working code on 1.6 – throws an error on 1.10rc. Also, the case with ConstructionBaseExtra doesn't throw any warning before 1.9 at all, no matter how you precompile it. |
…aching (#52214) Fixes #52213 Overwritting methods during cache creation is currently not something that the system can support and can lead to surprising, counter-intuitive and fatal errors. In 1.10 we turned it from a warning to a strong error, with this PR it remains a strong error, but the precompilation system recognizes it and essentially sets `__precompile__(false)` for this module and all modules that depend on it. Before: ``` julia> using OverwriteMethodError [ Info: Precompiling OverwriteMethodError [top-level] WARNING: Method definition +(Bool, Bool) in module Base at bool.jl:166 overwritten in module OverwriteMethodError at /home/vchuravy/src/julia2/OverwriteMethodError.jl:2. ERROR: LoadError: Method overwriting is not permitted during Module precompile. Stacktrace: [1] top-level scope @ ~/src/julia2/OverwriteMethodError.jl:2 [2] include @ Base ./Base.jl:489 [inlined] [3] include_package_for_output(pkg::Base.PkgId, input::String, depot_path::Vector{String}, dl_load_path::Vector{String}, load_path::Vector{String}, concrete_deps::Vector{Pair{Base.PkgId, UInt128}}, source::Nothing) @ Base ./loading.jl:2216 [4] top-level scope @ stdin:3 in expression starting at /home/vchuravy/src/julia2/OverwriteMethodError.jl:1 in expression starting at stdin:3 ERROR: Failed to precompile OverwriteMethodError [top-level] to "/home/vchuravy/.julia/compiled/v1.10/jl_guiuCQ". Stacktrace: [1] error(s::String) @ Base ./error.jl:35 [2] compilecache(pkg::Base.PkgId, path::String, internal_stderr::IO, internal_stdout::IO, keep_loaded_modules::Bool) @ Base ./loading.jl:2462 [3] compilecache @ Base ./loading.jl:2334 [inlined] [4] (::Base.var"#968#969"{Base.PkgId})() @ Base ./loading.jl:1968 [5] mkpidlock(f::Base.var"#968#969"{Base.PkgId}, at::String, pid::Int32; kwopts::@kwargs{stale_age::Int64, wait::Bool}) @ FileWatching.Pidfile ~/.julia/juliaup/julia-1.10.0-rc1+0.x64.linux.gnu/share/julia/stdlib/v1.10/FileWatching/src/pidfile.jl:93 [6] #mkpidlock#6 @ FileWatching.Pidfile ~/.julia/juliaup/julia-1.10.0-rc1+0.x64.linux.gnu/share/julia/stdlib/v1.10/FileWatching/src/pidfile.jl:88 [inlined] [7] trymkpidlock(::Function, ::Vararg{Any}; kwargs::@kwargs{stale_age::Int64}) @ FileWatching.Pidfile ~/.julia/juliaup/julia-1.10.0-rc1+0.x64.linux.gnu/share/julia/stdlib/v1.10/FileWatching/src/pidfile.jl:111 [8] #invokelatest#2 @ Base ./essentials.jl:889 [inlined] [9] invokelatest @ Base ./essentials.jl:884 [inlined] [10] maybe_cachefile_lock(f::Base.var"#968#969"{Base.PkgId}, pkg::Base.PkgId, srcpath::String; stale_age::Int64) @ Base ./loading.jl:2977 [11] maybe_cachefile_lock @ Base ./loading.jl:2974 [inlined] [12] _require(pkg::Base.PkgId, env::String) @ Base ./loading.jl:1964 [13] __require_prelocked(uuidkey::Base.PkgId, env::String) @ Base ./loading.jl:1806 [14] #invoke_in_world#3 @ Base ./essentials.jl:921 [inlined] [15] invoke_in_world @ Base ./essentials.jl:918 [inlined] [16] _require_prelocked(uuidkey::Base.PkgId, env::String) @ Base ./loading.jl:1797 [17] macro expansion @ Base ./loading.jl:1784 [inlined] [18] macro expansion @ Base ./lock.jl:267 [inlined] [19] __require(into::Module, mod::Symbol) @ Base ./loading.jl:1747 [20] #invoke_in_world#3 @ Base ./essentials.jl:921 [inlined] [21] invoke_in_world @ Base ./essentials.jl:918 [inlined] [22] require(into::Module, mod::Symbol) @ Base ./loading.jl:1740 ``` After: ``` julia> using OverwriteMethodError ┌ Info: Precompiling OverwriteMethodError [top-level] └ @ Base loading.jl:2486 WARNING: Method definition +(Bool, Bool) in module Base at bool.jl:166 overwritten in module OverwriteMethodError at /home/vchuravy/src/julia2/OverwriteMethodError.jl:2. ERROR: Method overwriting is not permitted during Module precompile. ┌ Info: Skipping precompilation since __precompile__(false). Importing OverwriteMethodError [top-level]. └ @ Base loading.jl:2084 ``` --------- Co-authored-by: Kristoffer Carlsson <[email protected]>
…aching (#52214) Fixes #52213 Overwritting methods during cache creation is currently not something that the system can support and can lead to surprising, counter-intuitive and fatal errors. In 1.10 we turned it from a warning to a strong error, with this PR it remains a strong error, but the precompilation system recognizes it and essentially sets `__precompile__(false)` for this module and all modules that depend on it. Before: ``` julia> using OverwriteMethodError [ Info: Precompiling OverwriteMethodError [top-level] WARNING: Method definition +(Bool, Bool) in module Base at bool.jl:166 overwritten in module OverwriteMethodError at /home/vchuravy/src/julia2/OverwriteMethodError.jl:2. ERROR: LoadError: Method overwriting is not permitted during Module precompile. Stacktrace: [1] top-level scope @ ~/src/julia2/OverwriteMethodError.jl:2 [2] include @ Base ./Base.jl:489 [inlined] [3] include_package_for_output(pkg::Base.PkgId, input::String, depot_path::Vector{String}, dl_load_path::Vector{String}, load_path::Vector{String}, concrete_deps::Vector{Pair{Base.PkgId, UInt128}}, source::Nothing) @ Base ./loading.jl:2216 [4] top-level scope @ stdin:3 in expression starting at /home/vchuravy/src/julia2/OverwriteMethodError.jl:1 in expression starting at stdin:3 ERROR: Failed to precompile OverwriteMethodError [top-level] to "/home/vchuravy/.julia/compiled/v1.10/jl_guiuCQ". Stacktrace: [1] error(s::String) @ Base ./error.jl:35 [2] compilecache(pkg::Base.PkgId, path::String, internal_stderr::IO, internal_stdout::IO, keep_loaded_modules::Bool) @ Base ./loading.jl:2462 [3] compilecache @ Base ./loading.jl:2334 [inlined] [4] (::Base.var"#968#969"{Base.PkgId})() @ Base ./loading.jl:1968 [5] mkpidlock(f::Base.var"#968#969"{Base.PkgId}, at::String, pid::Int32; kwopts::@kwargs{stale_age::Int64, wait::Bool}) @ FileWatching.Pidfile ~/.julia/juliaup/julia-1.10.0-rc1+0.x64.linux.gnu/share/julia/stdlib/v1.10/FileWatching/src/pidfile.jl:93 [6] #mkpidlock#6 @ FileWatching.Pidfile ~/.julia/juliaup/julia-1.10.0-rc1+0.x64.linux.gnu/share/julia/stdlib/v1.10/FileWatching/src/pidfile.jl:88 [inlined] [7] trymkpidlock(::Function, ::Vararg{Any}; kwargs::@kwargs{stale_age::Int64}) @ FileWatching.Pidfile ~/.julia/juliaup/julia-1.10.0-rc1+0.x64.linux.gnu/share/julia/stdlib/v1.10/FileWatching/src/pidfile.jl:111 [8] #invokelatest#2 @ Base ./essentials.jl:889 [inlined] [9] invokelatest @ Base ./essentials.jl:884 [inlined] [10] maybe_cachefile_lock(f::Base.var"#968#969"{Base.PkgId}, pkg::Base.PkgId, srcpath::String; stale_age::Int64) @ Base ./loading.jl:2977 [11] maybe_cachefile_lock @ Base ./loading.jl:2974 [inlined] [12] _require(pkg::Base.PkgId, env::String) @ Base ./loading.jl:1964 [13] __require_prelocked(uuidkey::Base.PkgId, env::String) @ Base ./loading.jl:1806 [14] #invoke_in_world#3 @ Base ./essentials.jl:921 [inlined] [15] invoke_in_world @ Base ./essentials.jl:918 [inlined] [16] _require_prelocked(uuidkey::Base.PkgId, env::String) @ Base ./loading.jl:1797 [17] macro expansion @ Base ./loading.jl:1784 [inlined] [18] macro expansion @ Base ./lock.jl:267 [inlined] [19] __require(into::Module, mod::Symbol) @ Base ./loading.jl:1747 [20] #invoke_in_world#3 @ Base ./essentials.jl:921 [inlined] [21] invoke_in_world @ Base ./essentials.jl:918 [inlined] [22] require(into::Module, mod::Symbol) @ Base ./loading.jl:1740 ``` After: ``` julia> using OverwriteMethodError ┌ Info: Precompiling OverwriteMethodError [top-level] └ @ Base loading.jl:2486 WARNING: Method definition +(Bool, Bool) in module Base at bool.jl:166 overwritten in module OverwriteMethodError at /home/vchuravy/src/julia2/OverwriteMethodError.jl:2. ERROR: Method overwriting is not permitted during Module precompile. ┌ Info: Skipping precompilation since __precompile__(false). Importing OverwriteMethodError [top-level]. └ @ Base loading.jl:2084 ``` --------- Co-authored-by: Kristoffer Carlsson <[email protected]> (cherry picked from commit 9e8fe68)
…aching (JuliaLang#52214) Fixes JuliaLang#52213 Overwritting methods during cache creation is currently not something that the system can support and can lead to surprising, counter-intuitive and fatal errors. In 1.10 we turned it from a warning to a strong error, with this PR it remains a strong error, but the precompilation system recognizes it and essentially sets `__precompile__(false)` for this module and all modules that depend on it. Before: ``` julia> using OverwriteMethodError [ Info: Precompiling OverwriteMethodError [top-level] WARNING: Method definition +(Bool, Bool) in module Base at bool.jl:166 overwritten in module OverwriteMethodError at /home/vchuravy/src/julia2/OverwriteMethodError.jl:2. ERROR: LoadError: Method overwriting is not permitted during Module precompile. Stacktrace: [1] top-level scope @ ~/src/julia2/OverwriteMethodError.jl:2 [2] include @ Base ./Base.jl:489 [inlined] [3] include_package_for_output(pkg::Base.PkgId, input::String, depot_path::Vector{String}, dl_load_path::Vector{String}, load_path::Vector{String}, concrete_deps::Vector{Pair{Base.PkgId, UInt128}}, source::Nothing) @ Base ./loading.jl:2216 [4] top-level scope @ stdin:3 in expression starting at /home/vchuravy/src/julia2/OverwriteMethodError.jl:1 in expression starting at stdin:3 ERROR: Failed to precompile OverwriteMethodError [top-level] to "/home/vchuravy/.julia/compiled/v1.10/jl_guiuCQ". Stacktrace: [1] error(s::String) @ Base ./error.jl:35 [2] compilecache(pkg::Base.PkgId, path::String, internal_stderr::IO, internal_stdout::IO, keep_loaded_modules::Bool) @ Base ./loading.jl:2462 [3] compilecache @ Base ./loading.jl:2334 [inlined] [4] (::Base.var"JuliaLang#968#969"{Base.PkgId})() @ Base ./loading.jl:1968 [5] mkpidlock(f::Base.var"JuliaLang#968#969"{Base.PkgId}, at::String, pid::Int32; kwopts::@kwargs{stale_age::Int64, wait::Bool}) @ FileWatching.Pidfile ~/.julia/juliaup/julia-1.10.0-rc1+0.x64.linux.gnu/share/julia/stdlib/v1.10/FileWatching/src/pidfile.jl:93 [6] #mkpidlock#6 @ FileWatching.Pidfile ~/.julia/juliaup/julia-1.10.0-rc1+0.x64.linux.gnu/share/julia/stdlib/v1.10/FileWatching/src/pidfile.jl:88 [inlined] [7] trymkpidlock(::Function, ::Vararg{Any}; kwargs::@kwargs{stale_age::Int64}) @ FileWatching.Pidfile ~/.julia/juliaup/julia-1.10.0-rc1+0.x64.linux.gnu/share/julia/stdlib/v1.10/FileWatching/src/pidfile.jl:111 [8] #invokelatest#2 @ Base ./essentials.jl:889 [inlined] [9] invokelatest @ Base ./essentials.jl:884 [inlined] [10] maybe_cachefile_lock(f::Base.var"JuliaLang#968#969"{Base.PkgId}, pkg::Base.PkgId, srcpath::String; stale_age::Int64) @ Base ./loading.jl:2977 [11] maybe_cachefile_lock @ Base ./loading.jl:2974 [inlined] [12] _require(pkg::Base.PkgId, env::String) @ Base ./loading.jl:1964 [13] __require_prelocked(uuidkey::Base.PkgId, env::String) @ Base ./loading.jl:1806 [14] #invoke_in_world#3 @ Base ./essentials.jl:921 [inlined] [15] invoke_in_world @ Base ./essentials.jl:918 [inlined] [16] _require_prelocked(uuidkey::Base.PkgId, env::String) @ Base ./loading.jl:1797 [17] macro expansion @ Base ./loading.jl:1784 [inlined] [18] macro expansion @ Base ./lock.jl:267 [inlined] [19] __require(into::Module, mod::Symbol) @ Base ./loading.jl:1747 [20] #invoke_in_world#3 @ Base ./essentials.jl:921 [inlined] [21] invoke_in_world @ Base ./essentials.jl:918 [inlined] [22] require(into::Module, mod::Symbol) @ Base ./loading.jl:1740 ``` After: ``` julia> using OverwriteMethodError ┌ Info: Precompiling OverwriteMethodError [top-level] └ @ Base loading.jl:2486 WARNING: Method definition +(Bool, Bool) in module Base at bool.jl:166 overwritten in module OverwriteMethodError at /home/vchuravy/src/julia2/OverwriteMethodError.jl:2. ERROR: Method overwriting is not permitted during Module precompile. ┌ Info: Skipping precompilation since __precompile__(false). Importing OverwriteMethodError [top-level]. └ @ Base loading.jl:2084 ``` --------- Co-authored-by: Kristoffer Carlsson <[email protected]>
Tried out 1.10rc for a bit recently, and got this error a few times:
ERROR: LoadError: Method overwriting is not permitted during Module precompile.
As I understand, this error was added deliberately, which really surprised me: it's basically the definition of a breaking change, explicitly making code that worked fine before to error now.
In previous versions, this was a warning that only appeared during precompilation (so users rarely even saw it), and it didn't really indicate that the code uses some internals and could break after updating Julia:
I even found a discourse thread (https://discourse.julialang.org/t/what-is-incremental-compilation-and-what-does-it-mean-for-it-to-be-broken/100956) where Tim Holy directly states that everything is supposed to work with this warning, just with slower compilation/loading/invalidations.
So, should this breaking change be reverted?
And, probably, the warning text made cleaner: I saw it several times, but never had an idea what "incremental compilation" means and why would I be worried about it. Looking at discussions, I'm not alone in this.
See a recent slack thread https://julialang.slack.com/archives/C67910KEH/p1699434379137429 for more discussion and examples.
The text was updated successfully, but these errors were encountered: