(k, a, b, a1, b1) = (BigInt(2), BigInt(4), BigInt(1), BigInt(12), BigInt(4))
while k <= BigInt(4)
(p, q, k) = (k*k, BigInt(2)*k+BigInt(1), k+BigInt(1))
end
This code compiles and runs in Julia 0.6, but in 1.0 produces ERROR: UndefVarError: k not defined
.
Did something change between versions? What's wrong with this code in Julia 1.0?
Yes, something changed. I think this is what's going on:
Assigning to
p
,q
, andk
inside the loop does actually creates newp
,q
, andk
bindings in a new local scope. Then, becausek
is also used on the right-hand side, Julia tries to use the localk
and fails.In order to obtain the expected semantics (mutating the existing
p
,q
, andk
defined at the top level), you need to declare them "global" first:edit: thanks to user AnAverageHuman on Freenode for figuring this out.
The answer by shadowtalker is correct. However, there is one important issue with this code that is worth adding some more explanation (and it was too long for a comment).
The relevant scoping rules in Julia for this case are the following (and if you want to read the details you can find them here https://docs.julialang.org/en/latest/manual/variables-and-scoping/#Local-Scope-1):
while
block introduces a new local scope;global
keyword as explained by shadowtalker);local
keyword.Now - why this is important? The reason is that your code will behave differently if you run it in global scope (e.g. in Julia REPL) and differently if you have it in a local scope (e.g. inside a function).
If you run it in global scope then what shadowtalker showed is needed. However, if yourun it e.g. inside a function you do not have to change anything. For example this function will work correctly:
also without creating a function if you e.g. use
let
block in a global scope the code will just run as intended:because
let
creates a local scope (I have added the statement at the end oflet
block to make it evaluate to the values of the introduced variables so that you can inspect them).This is a significant change from Julia 0.6 and earlier where Julia made a difference between hard and soft local scopes (see here https://docs.julialang.org/en/release-0.6/manual/variables-and-scoping/#scope-of-variables-1), but this distinction is gone - all local scopes now behave identically. This is a significant change an in practice it means that you can expect that the code that runs correctly inside some local scope (a function in most cases) will change its behavior if you copy-paste it to a global scope. From my experience using
let
blocks as shown above is the simplest way alleviate this problem.