Const vs zero argument function

In Julia, we have both trivial zero argument functions and constants

a() = 7
const A = 8

Both support constant propagation:

f(x) = x+a()
g(x) = x+A
@code_llvm f(0)
;  @ REPL[3]:1 within `f`
define i64 @julia_f_140(i64 signext %0) #0 {
; ┌ @ int.jl:87 within `+`
   %1 = add i64 %0, 7
; └
  ret i64 %1
@code_llvm g(0)
;  @ REPL[4]:1 within `g`
define i64 @julia_g_163(i64 signext %0) #0 {
; ┌ @ int.jl:87 within `+`
   %1 = add i64 %0, 8
; └
  ret i64 %1

But zero-argument functions can be redefined and constants can’t be. What prevents redefining constants?

1 Like

Compiled methods which depend on the type or value of a constant would need to have “back edges” to the constant and the system would have to arrange for assigning a new type or value to a constant to increase the world age and cause invalidated methods to be recompiled. Note that new methods don’t affect any calls that occur in code that’s already running in an older world and code isn’t run in a new world until it is I’m called with invokelatest or eval. So changing method definitions does not work the way people expect assigning to a global variable to work, which would be to have an immediately visible effect everywhere. That might be acceptable for redefinitions of constants, and would allow us to make the warning that is printed less dire. It would also entail keeping multiple different versions of module bindings for different worlds, which is certainly doable, but might be unexpected.


Thank you for your explanation!

If global constants were implemented the way you describe, could the waring read “WARNING: redefinition of constant A. This will only take effect after reaching toplevel.” and have no warning when constants are redefined at the toplevel? If so, that seems like a nice improvement over “WARNING: redefinition of constant A. This may fail, cause incorrect answers, or produce other errors.”

You mentioned “back edges” I imagine all methods already have back edges to the methods they call. Would there be a substantial performance penalty for adding back edges for constants?

Yes, methods already have back edges to methods they call, that’s how method invalidation/overwriting works. I think the redefinition of a constant should always emit a warning—after all it’s constant. This would just make the behavior reliable for interactive usage.


I’m not an expert, but my understanding is that we are essentially trying to have as few backedges as we can get away with, because inserting backedges slows down compilation, and makes julia’s ambient memory footprint larger. So proposals that involve inserting backedges for new things need to demonstrate a significant benefit that outweighs the costs.