Add support for not triggering invalidation in load_preference()#90
Conversation
In some cases it's desirable to use Preferences.jl as a generic preferences mechanism without wanting it to affect precompilation.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #90 +/- ##
==========================================
+ Coverage 92.65% 93.82% +1.16%
==========================================
Files 2 2
Lines 177 178 +1
==========================================
+ Hits 164 167 +3
+ Misses 13 11 -2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
(bump) |
1 similar comment
|
(bump) |
|
I think this is useful, but I’d like to name it something a little more clear; perhaps “disable_invalidation”, to communicate to the user that (a) this is disabling something, and (b) it’s not really stopping this from happening at compile time. |
|
Sure, renamed in 1f17881. |
|
I don't know that I like this. If you're not using the preference to affect the ouput, then why are you reading it at compile time? If the issue is that it's hard to separate the code paths, then I'd rather have an API that returns a fixed value at precompile time every time and only does the dynamic thing at runtime. |
|
I can see the use for this for e.g. functions that get called incidentally during compilation, but are not intended to be invalidating. I wanted this kwarg to sound a little dangerous (hence the I'm not certain if the "fixed value at precompile time" idea is better; I do like reducing potential sources of nondeterminism, although I am a little worried that such behavior will be endlessly confusing to developers. Ideally though, very few people are using such a feature. |
The consequence for getting this kwarg wrong may include arbitrary undefined behavior. That will be more than a little confusing. |
|
What if we made a new function for it named e.g. |
|
But why, I don't get it. Either the preference value matters or it doesn't. It it doesn, it's a big problem. If it doesn't, then any arbitrary value should be fine, so might as well make that the interface. |
|
If we're going to replace the preference with an arbitrary value during precompilation then we might as well just make it throw an exception, because that's what most likely will happen when the user code tries to do something with it (like compare it with a boolean), and that's not really useful. Like, in IJulia I would use it for getting the Jupyter path and I would call the |
Doesn't it? What happens if jupyter is not installed, so it early-outs and now you've got a poisoned cache. |
|
That's an expected case to handle so it would go for a fallback path, but in any case how would it cause a 'poisoned' cache? A preference not being set is normal, an early exit just means some code won't get executed just like it wouldn't if some boolean variable was not set. |
|
The precompile wouldn't run, so you'd be perpetually left with a slow starting IJulia for reasons that nobody can figure out. |
|
I wouldn't call that a 'poisoned' cache; it's just incomplete, exactly the same situation as if the setting was obtained from an environment variable or scratch file. Unless I'm missing something, using Preferences here does not make things any worse in that scenario? To give more context, the main reason I'd like to use Preferences is because it allows for persistent storage in a single, familiar format to users. One could also use Scratch.jl for persistence but that's not standardized, and if Preferences is already used for some settings that do require cache invalidation then it makes sense to re-use that for other settings even though they may not require cache invalidation. |
|
(I acknowledge I'm biased a bit towards user-friendliness, which is why I think this is a reasonable tradeoff) |
|
Yes, there's a million ways to do unsound things during precompile without the compiler catching you (although the compiler will get better at it and we may start doing things like running in a sanitized environment), but the issue here is that Preferences was specifically designed to be precompile-safe. I don't think it's a good idea to add a keyword argument that pokes a giant hole into those safety guarantees. Being precompile-safe is pretty much the whole point of this design - it's not a quirky afterthought. |
|
I dunno, as I said I feel it's an ok tradeoff 🤷 It's intentionally not accessible through the |
|
Can I get a final yea/nay before starting to use it? |
|
I think we should revert this PR. @staticfloat ? |
|
Just to add my $.02: I think there is a use case to compute paths that do not "meaningfully" affect the result of your pre-compilation (to the extent that they are different locations of "effectively" the same file). This is how the That said, I think the Preferences API makes it too easy to not consider version swaps, etc. that might make your package logic incorrect. It also puts package authors (such as IJulia) in the uncomfortable position of wanting not to invalidate since "most" path overrides won't change program (major / minor) versions, but some will which leaves surprising / broken behavior floating around for users as @Keno explains. The Artifacts / JLL system is clearer that if you provide an "override" it should be for exactly the same file / version, which makes it relatively safe for packages to query API's, data structures, etc. at compile-time and expect the "same" thing at runtime.
FWIW unfortunately, there are some notable holes in the pre-compile dependency tracking. Some are just bugs (JuliaLang/julia#59344), but other gaps may have been left on purpose due to wanting to avoid generating "accidental" dependencies in I am still in favor of being more strict about these though, so I will probably push forward a "fix" soon. |
|
I’ve thought about this more and I agree with Keno that we shouldn’t give access to more footguns if we can help it. I think a happy middle ground would be to change the API here such that disable_invalidation actually means “always return the default value during compilation”. Maybe we change the keyword argument name to “force_compiletime_default_value” or some such. |
|
Ok, that works for me 👍 I'll make a PR in a bit. |
In some cases it's desirable to use Preferences.jl as a generic preferences mechanism without wanting it to affect precompilation.
Some examples:
Mostly generated by Claude 🤖