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

scoping issues, part 2 #424

Closed
alexalemi opened this issue Feb 20, 2012 · 9 comments
Closed

scoping issues, part 2 #424

alexalemi opened this issue Feb 20, 2012 · 9 comments
Labels
breaking This change will break code needs decision A decision on this change is needed speculative Whether the change will be implemented is speculative
Milestone

Comments

@alexalemi
Copy link

Very interesting language, however there seems to be a rather nasty bug in the way while loops handle variables.
The following code

x = 0
while x < 10
    println(x)
    x += 1
end

if entered into the julia intepreter as two lines, works. Something like it even appears as an example in the manual, but as a script, executed as julia testloop.j, gives the following error

x not defined
in include, src/boot.j:192
in process_options, pathtojulia/julia/j/client.j:163
in _start, pathtojulia/julia/j/client.j:201
at testloop.j:2

Similarly, loading the script with

load("testloop.j")

gives the same error on the first load, but not on subsequent loads.

@JeffBezanson
Copy link
Member

Believe it or not, this is somewhat intentional and there is a reason it behaves this way, but I agree it might be bad.

Normally variables are inherited by inner scopes (the body of the while is an inner scope), but this does not apply to global variables if the variable is assigned to. In other words, to assign to a global variable you have to declare it as global in that scope. This (1) flags possible non-local effects, and (2) discourages global variables.

Using global variables this way tends to be very slow, since the compiler can't see all uses of the variable, and it might be reassigned anywhere (for example inside the println function).

We made an exception to this in the REPL, since there you generally want all your top-level variables to be visible everywhere in your inputs. Maybe this was a mistake, and we should either use the REPL behavior everywhere, or the other behavior everywhere (including in the REPL).

@alexalemi
Copy link
Author

So, just curious, how would I make the above script function as a script, since changing the first line to global x=0 doesn't change it's behavior, and putting global in the while test breaks it as well.

@JeffBezanson
Copy link
Member

The following works:

x = 0

while x < 10
    println(x)
    global x += 1
end

But, best is to put the whole thing inside function main() and then call main().

@StefanKarpinski
Copy link
Member

Two obvious ways to do this. The first is to put the whole thing in a let block since that makes the scope local rather than global:

let
  x = 0
  while x < 10
    println(x)
    x += 1
  end
end

The other way is to just use a for loop:

for x = 0:9
  println(x)
end

This is admittedly an awkward design for global variables — but that's kind of the point — we want to discourage global variables as much as possible. @JeffBezanson, would it be possible for this error to have a more helpful error message, instructing the user how to accomplish what they want?

@aviks
Copy link
Member

aviks commented Mar 18, 2012

In the last month of writing julia programs, I've struggled with the global scoping rules. It took quite a while to reach my epiphany. The biggest source of confusion was that examples in the manual ran in the repl, but not in my scripts.

But once it clicked, it does make a lot of sense. Quite like the heavy handed syntax for globals.

@StefanKarpinski
Copy link
Member

Yeah, we need to fix this. I think the strong/weak scope proposal I came up with makes this distinction go away. If we also make expressions in the repl auto-let all the variables they use, then the performance issues can also go away. I think the former is more important by far though.

@JeffBezanson
Copy link
Member

I agree, but it's also important not to use global variables. The reason we put up with this behavior instead of fixing it long ago is that we don't use global variables. The needed epiphany is this: don't use global variables. Also, don't use global variables.

In conclusion, I recommend not using global variables.

@pao
Copy link
Member

pao commented Mar 18, 2012

I think restricting scope of variables in scripts (loading scripts in an auto-let block) so the variables don't leak to other scripts or the REPL is a better idea than having top-level script variables be global in the first place. But perhaps that's just me. And Python; unless you explicitly from foo import *--the top-level variables are hiding in the foo namespace on a normal import.

@StefanKarpinski
Copy link
Member

I support @pao's proposal or something like it. The basic issue is just that running code in a script by itself and in a function body currently don't work the same.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking This change will break code needs decision A decision on this change is needed speculative Whether the change will be implemented is speculative
Projects
None yet
Development

No branches or pull requests

5 participants