George Datseris
George Datseris

Reputation: 411

Get rid of Julia's `WARNING: redifining constant` for strings that are not changed?

In my julia code I am using some constants. Some of these constants are strings (they serve as identifiers). My issues is that whenever I run a julia script, I always get the following warning for constant strings, even when I do not change the constants : WARNING: redefining constant pot_type

To illustrate my problem, here is a MWE:

const pot_type = "constant"
const b = 12
println("Given parameters: Potential = $pot_type, b = $b .")

If I run this script two times, I will get the aforementioned warning. Not only that, but the same thing will happen if I just type const something = "somestring" two times in the Julia console. I just get WARNING: redefining constant something.

I am aware that this does not affect my code in any way, but is there anyway to remove this warning or to fix it? In my actual code it creates 5 lines every time I submit something and this space could be used to display the output of previous submissions.

EDIT (making myself clearer): The problem is that this WARNING message is displayed even when I am NOT redefining a constant, meaning that I give it the same value. And also, this problem (as far as I know) exists ONLY for String , not for Int64 or Float64 types. E.g.: if I write const b = 1.2 and then const b = 1.4 I will get the warning message as expected. Now, if I write const b = 1.2 and then const b = 1.2 (same value), I will NOT get the warning, again as expected. However this does not work with string constants. You will get the warning even when defining the same value.

Upvotes: 2

Views: 2002

Answers (3)

user1211719
user1211719

Reputation: 31

Just a quick update to Michael Ohlrogge's answer as noted by L.Grozinger in the comments. As of Julia v1.6 the format should be (for a given const x = 10)

(@isdefined x) || (const x = 10)

Upvotes: 2

StefanKarpinski
StefanKarpinski

Reputation: 33259

To complement and elaborate on @aireties' excellent answer, there are three cases currently in Julia when you do const x = a and later do const x = b again in the same module:

  1. No warning: if a === b then a and b are programmatically indistinguishable in the sense of Henry Baker's EGAL [1, 2]: replacing a with b cannot affect the behavior of any program, so this redefinition of the constant x is a no-op and no warning is needed.

  2. Warning: if a !== b but typeof(a) == typeof(b) then in the current version of Julia, the generated code remains valid because it only depends on the type of x, which remains unchanged, but the behavior of the program is potentially affected by the change to x since the old value a and the new value b are programmatically distinguishable.

  3. Error: if typeof(a) != typeof(b) the reassignment of x would invalidate the assumptions of any previously generated code using x. Therefore this assignment is not allowed.

The === predicate compares immutable values by type and content so 1.5 is always the same as 1.5 since no matter how many "instances" of this value you have, they cannot be mutated and therefore cannot be distinguished in any way. The values 1.5 (Float64) and Float32(1.5), on the other hand, are distinguishable since they have different types, even though they represent the exact same numerical value. For mutable values, however, the === predicate compares objects by identity: unless they are the exact same object, they are not considered to be ===. This is because you can programmatically distinguish two mutable values, even if they start out with equal values, by changing one of them and seeing if the other one changes or not.

In Julia, strings are immutable by convention only: the String type wraps an array of bytes, which is mutable; the String type just doesn't expose any functions which modify those bytes. You can still – and this is not advised in most programs – reach in and mutate the bytes of a string. This means that two different instances of equal string values are different objects and therefore not === to each other. Thus, when you do const x = "foo" and later const x = "foo" again, you are assigning two different !== string objects to x so you get the warning that you're asking about:

julia> const x = "foo"
"foo"

julia> const x = "foo"
WARNING: redefining constant x
"foo"

If, on the other hand, you assign the same string object to x twice, you get no warning:

## in a new session ##

julia> foo = "foo"
"foo"

julia> const x = foo
"foo"

julia> const x = foo
"foo"

In the future, we might change the implementation of String so that it is actually immutable, in which case updating a const binding with and equal string value of the same type would no longer produce a warning since those two values would be === to each other.

Upvotes: 4

Michael Ohlrogge
Michael Ohlrogge

Reputation: 10990

If you are going to use something as a constant then you really don't want to be defining it multiple times (after all, that's the point of a constant) and when you run your script multiple times, that's exactly what you are doing. Also, it's not quite true that redefining constants doesn't affect your code in any way - it actually can hurt performance quite a bit in some situations. Again, that's why you use constants - to improve performance by making explicit that the computer doesn't need to worry about particular objects having their values changed.

Even if you are assigning the constant the same value, it's still going to look like a new assignment to the computer. I.e. the computer won't, at least without you more explicitly telling it to (as I describe below) perform some additional logic to see "oh, I guess this is just the same value that is getting assigned to the constant that it had before, I suppose that's probably ok."

In general, situations where you are running the same script multiple times just arise in development, which I am guessing is what you're doing. Thus, as a quick fix to this, you could check to see if your constant is already defined and only assign it a value if it isn't. The following will accomplish that:

isdefined(:b) || (const b = 12)

As a longer term solution, once you get past the development stage (where you keep running the same bit of code again and again to get the bugs worked out) then you'll really want to write your script so that it doesn't get to defining a constant multiple times, since otherwise, as I mentioned, it's not really a constant in that case.

P.S. in case it's helpful, the interpretation of the above code snippet is as follows. The || operator means that Julia will evaluate the first statement isdefined(:b) and only go on to the second statement, (const b = 12) if the first is false. We use the : operator in the first statement to refer to the symbol for b, i.e. to ask is there anything assigned to that symbol, b.

Upvotes: 6

Related Questions