Does declaring a variable to be constant do anything at all?

The code

const x = 4
x = 3

issues a warning but still changes the value of x. And you can change bits-type fields of constant instances of mutable types without even getting a warning:

mutable struct Mut
  x::Int64
end

const myMut = Mut(5)
myMut.x = 6

What is the point of constant variables if they can be changed? Apparently declaring global variables to be constant can improve performance - but if they’re not actually constant, then are you getting that speedup for free?

Declaring them constant fixes the type, which is what improves performance. This is enforced, eg

julia> const x = 42
42

julia> x = 2.71
ERROR: invalid redefinition of constant x
4 Likes

Besides the constant type which is useful for performance in the global scope, constant values do actually get inlined into functions. For example:

julia> const a = 5
5

julia> f(x) = a
f (generic function with 1 method)

julia> @code_llvm f(2.)

define i64 @julia_f_60745(double) #0 !dbg !5 {
top:
  ret i64 5
}

julia> a = 12
WARNING: redefining constant a
12

julia> @code_llvm f(3.)

define i64 @julia_f_60760(double) #0 !dbg !5 {
top:
  ret i64 5
}

Here we see that you are not getting the speedup for free. Changing the constant is allowed, but the function trusts that you won’t do this and doesn’t check the value again.

12 Likes

I see, thanks. As I mentioned above, there appears to be a slight inconsistency in the warning behavior triggered by changing constants: changing the value of a constant variable itself triggers a warning, but changing the value of a field (even a bits-type field) of a constant instance of a mutable composite type does not. Shouldn’t the latter action also trigger a warning, for consistency?

No, the constness is on the binding, not the object being “pointed” at.

2 Likes

Am I correct in understanding the difference as being that reassigning a global variable writes the new value to a new memory location and then rebinds the variable to the new memory location, whereas reassigning a field of a composite type overwrites the new value in the same memory location as the old data, so that the field’s binding doesn’t change?

No, the field binding can very well change. The constness is not on the field binding but of the binding from the variable to the object.

Perhaps this is useful reading: Values vs. Bindings: The Map is Not the Territory · John Myles White.

1 Like

Oh, I see, when you said “the constness is on the binding” you were referring to the binding of the variable “myMut” to the particular object. I thought you were referring to the binding of the field “myMut.x” to 5.

No the two concepts are orthogonal. You shouldn’t describe mutating an object as binding. I’m not sure what background you have (i.e. what languages are you familiar with) but I’ll try and point out that variables are orthorgonal to object in julia, just like most scripting languages. This is unlike C++ for example, where variables basically equal objects. Immutable means, well, you can’t mutate an object. Constant global means you can’t change the object it’s pointing to.

I understand, thanks.

No. immutable is unrelated to no-rebinding. I would have said you can rebind immutable just fine but this sentense itself would not make any sense.
Basically type is not the property of a name (variable) and mutability is a property of the type so you can’t talk about something being immutable and having it being the subject of binding. Such a concept doesn’t exist.

To give examples. You can assign a immutable type to a variable and assign anything else to the same variable. The variable holding a immutable type currently does not affect what else you can put in it.

OTOH, (this you already mentioned) you can have a constant global whose value is a mutable type. You can’t change which object the variable points to but you can mutate the value just fine.