While without global

2020-01-29 03:04发布

问题:

This snippet of code is from JuliaBoxTutorials

myfriends = ["Ted", "Robyn", "Barney", "Lily", "Marshall"]
i = 1;

while i <= length(myfriends)
    friend = myfriends[i]
    println("Hi $friend, it's great to see you!")
    i += 1
end

giving this error when run with Julia v1.0

UndefVarError: i not defined

Stacktrace:
 [1] top-level scope at ./In[12]:5 [inlined]
 [2] top-level scope at ./none:0

But when i += 1 is replaced with global i += 1 it works. I guess this was still working in v0.6 and the tutorial will be adapted once the new Intro to Julia is published this Friday.

I was just wondering, is it possible, to make a while loop without stating a global variable?

回答1:

As @Michael Paul and @crstnbr already replied in the comments, the scoping rules have been changed (Scope of variables in Julia). The for and while loop introduce a new scope and have no access to the outside (global) variables. You can get scope access using the global keyword but the recommended workflow is wrapping your code in functions.

One of the benefits of the new design is that the user is forced to avoid such global constructs which directly affect the performance of functions - which cannot be type stable when they access global variables.

One downside is the confusion when experimenting in the REPL and seeing such errors.

In my opinion the new behaviour is the cleaner one with respect to predictability. It was however a very tough and long-running discussion within the whole Julia community ;)

There is currently a discussion if the REPL will be changed to behave like the old one by making use of let-wraps: https://github.com/JuliaLang/julia/issues/28789 This is something which is not practical to be done manually (much more complicated then using the global keyword), see the example by Stefan Karpinski: https://github.com/JuliaLang/julia/issues/28789#issuecomment-414666648

Anyways, for the sake of completeness (although I would not recommend doing this) here is a version using global:

myfriends = ["Ted", "Robyn", "Barney", "Lily", "Marshall"]
i = 1;
N = length(myfriends)    

while i <= N  # you cannot even call a function here
              # with a global, like length(myfriends)
    global i, myfriends
    friend = myfriends[i]
    println("Hi $friend, it's great to see you!")
    i += 1
end

Note however that this is also completely valid:

myfriends = ["Ted", "Robyn", "Barney", "Lily", "Marshall"]

greet(friend) = println("Hi $friend, it's great to see you!")

for friend in myfriends
    greet(friend)
end


回答2:

I found that this works in Julia v1.0:

let 
    myfriends = ["Ted", "Robyn", "Barney", "Lily", "Marshall"]
    i = 1;

    while i <= length(myfriends) # this function here seems to work no problem
        friend = myfriends[i]
        println("Hi $friend, it's great to see you!")
        i = i + 1 # gives syntax error when prefixed with global 
    end
end

In fact, it will give me a syntax error if I try to make i global :) within the while loop.