Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scope query in assignment / misunderstanding ? #6522

Closed
johndrummond opened this issue Apr 14, 2014 · 4 comments
Closed

Scope query in assignment / misunderstanding ? #6522

johndrummond opened this issue Apr 14, 2014 · 4 comments

Comments

@johndrummond
Copy link

I've read #423 and #424 and the manual and I'm still not clear why the following happens and whether it's meant to. I'm hoping I've not done something stupid.

I put the following in a file and ran it with Julia 0.21 on windows
The last println prints
header without loop is => set in inner loop
why isn't it
header without loop is =>initialised
i.e. shouldn't the trade_header assignment in the for loop have created a new local variable?
I'm guessing that the trade_array should be considered as an assignment as I'm only changing the contents, not the array pointed to.

let
trade_array = (Any)[]
trade_header = "initialised"
for line in ([1:2])
    trade_header = "set in inner loop"
    push!(trade_array, [line])
    println(string(line, " header in inner loop is => ",trade_header))
end
println(trade_array)
println(string("header without loop is => ",trade_header))
end
@toivoh
Copy link
Contributor

toivoh commented Apr 14, 2014

Quoting from http://docs.julialang.org/en/release-0.2/manual/variables-and-scoping/ :

An assignment x = y introduces a new local variable x only if x is neither declared global nor explicitly introduced as local by any enclosing scope before or after the current line of code.

The assignment trade_header = "set in inner loop" inside the for loop doesn't introduce a new variable, because the variable trade_header is already in scope.

@johndrummond
Copy link
Author

thank you and I see that's the case even when I remove the let loop.
In which case my question should have been why in the code below results in
header without block is => initialised
as the result of the last println, i.e. the once I move into the open file loop trade_header isn't in scope. I note it is in scope if I wrap the code in a let loop, also that without the let loop the trade_array is in scope.
Thanks for your help - I'm wondering if there's something obvious I'm missing.

#test.txt contains 2 lines of numbers e.g. 1\t2\n3\t4\n
trade_header = "initialised"
trade_array = (Any)[]
open(string("c:/trash/test.txt"),"r") do f
  trade_header = chomp(readline(f))
  println(string("header in block is => ",trade_header))
  for line in eachline(f)
    trade_header ="set in inner loop"
    push!(trade_array, [line])
    println(string("header in inner loop is => ",trade_header))
  end
  println(string("header in block is => ",trade_header))
end
println(string("header without block is => ",trade_header))
println(trade_array)

@toivoh
Copy link
Contributor

toivoh commented Apr 15, 2014

You are hitting the gap between global and local variables.
The code trade_header = "initialised" is in global scope, so it creates a global variable.
The do syntax creates an anonymous function, so the assignment trade_header = chomp(readline(f)) does not find an enclosing local definition, and introduces a local variable. With a let block, the original trade_header assignment creates a local variable, which can be reassigned by default inside the anonymous function.

This irregularity between global and local variables has been discussed before. I think that Julia has also been patched up so that code outside of functions often seems to work similar to code inside functions, but this case seems hard to patch up. I for one would welcome a more regular treatment, but I'm not sure what would be a reasonable way forward. My best advice would probably be to write as little code in global scope as possible - it usually works as you expect, but not always.

@johndrummond
Copy link
Author

Thank you. That's very helpful. I'll follow your advice - for shorter scripts I can just wrap them in let blocks and have a liberal sprinkling of locals

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants