Understanding while loop UndedVarError and scope

julia> a=1; 

julia> while true; print(a);          break; end
1

julia> while true; q=2;               break; end

julia> while true; q=2; print(q);     break; end
2

julia> while true; print(q); q=2;     break; end

is an equivalent version of the code in OP.

I expected a to have a value for 2 reasons:

  1. a=1 present before the while loop. while loop body introducing by default a local scope is a strange (to say the least) idea to me
  2. once Julia can tell a is made local, even though a=2 occurs after print(a), somehow I expected it to also “see” the value on the other side of = in a=2.

I no longer hold the 2nd opinion (after your clarification of just syntactic determination of local scope.)
I still hold 1st opinion though, quite strongly. I will probably elaborate in another post, in “Development” section.

Not at all; my version illustrates the conflict between a local and global variable with same name, and user confusion it creates. Your version is not surprising at all, IMO.

The two versions are semantically equivalent. Your thread title was “Understanding while loop UndedVarError and scope”, my example was there to help you do that.

1 Like

Thank you. Now I see what you mean: they are semantically equivalent for the computer. With my reply above to you “Not quite…” I meant they are not equivalent from the user perspective/expectation.

I think you’re going to find this very helpful in your research. There’s no need for duplication of that topic.

1 Like

ONE MORE QUESTION HERE

I’ve been told repeatedly that An explicit global is needed to change a global variable.
Then why this works (again Repl, v 1.01) ?

julia> v=[0 0];
julia> while true; v[1]=1; break; end
julia> v
1×2 Array{Int32,2}:
1  0

global is needed to rebind a variable which is a completely different thing from mutating a container.

v[1] = 1 is just pretty syntax for setindex!(v, 1, 1).

OK.
But the effect is exactly the same as v=[1 0] !

I thought the intent of all these globals was to prevent modifying stuff in global scope unintentionally
From https://docs.julialang.org/en/v1/manual/variables-and-scoping/:

Avoiding changing the value of global variables is considered by many to be a programming best-practice.

This is all… overcomplicated.

No, it is definitely not.

Case 1, using v[1] = 1

v = [0 0]
x = v
v[1] = 1
x

printing x now shows [1 0].

Case 2, using v = [1 0]

v = [0 0]
x = v
v = [1 0]
x

printing x now shows [0 0].

Scoping is about what value (or object) a particular symbol is bound to. Assignment changes that. Mutation does not.

I don’t understand how your explanation is relevant to what I was saying (I don’t blame you).

I knew that in Julia assignment can bind several names to the same object, and mutating the object via one name results in all names pointing now to the new object

But in the context I talked about, I used only 1 name, v, and was stating that allowing v[1]=1 inside while to mutate global v would be the same as if Julia allowing direct v = [1 0] inside that loop to modify that same global v.

Scoping is about what value (or object) a particular symbol is bound to. Assignment changes that. Mutation does not.

With s =[0 0] , then does not s[1]=1 result in now symbol s being bound to a new object, [1 0], as compared to [0 0]?

(I don’t mean the internal implementation details, but the end result)

No, it means that the object s has been modified but it is the same object.

julia> s = [0 1];

julia> pointer_from_objref(s)
Ptr{Nothing} @0x000000010e6324d0

julia> s[1] = 1;

julia> pointer_from_objref(s) # the same as before
Ptr{Nothing} @0x000000010e6324d0

julia> s = [1 1];

julia> pointer_from_objref(s) # different, new object
Ptr{Nothing} @0x000000010ecf55d0

That’s sounds like a logical self-contradiction to me :face_with_monocle:

You are showing that with mutation, the address of the object remains the same: but then you interpret this to mean that the object stays the same as well.

I “prove” the “same-ness” of the 2 objects like this :slight_smile:

s=[0 0]; s[1] = 1;
s == [1 0]
true
s = [1 0];
s == [1 0]
true

It isn’t though. There is a difference between repainting a house and building a new identical house with a new color. As a case where this would matter, burning down the new identical house is likely ok while burning down the repainted house would likely get you in trouble with the people who own it.

Scope has to do with the bindings of symbols to objects, not the content of the objects.

Having different definitions than everyone else means that there will be trouble when you communicate with other people. I’ve already shown you where your definition of “same-ness” and two objects being identical matters.

3 Likes

This means that allowing to mutate a globally defined object is more dangerous than just creating a new one. Which even more supports my point that if you allow v[1]=1 inside loops, then you should allow v = [1 1] as well.

Having different definitions than everyone else means that there will be trouble when you communicate with other people.

True. But it seems like different people have different notions of “object”, depending on their background.
Do you have a reference to the definition of “object” in Julia documentation?
I could not find one, so I use an everyday notion.

A variable, in Julia, is a name associated (or bound) to a value.
(https://docs.julialang.org/en/v1/manual/variables/ )
An array is a collection of objects stored in a multi-dimensional grid. In the most general case, an array may contain objects of type Any .
(https://docs.julialang.org/en/v1/manual/arrays/ )

On the other hand, how to compare objects can be defined in different ways: ==, ===, (others?..)

I had the assumption here that you wanted to understand and learn how Julia scope behaved but this is more and more getting into just repeating Another possible solution to the global scope debacle so I’ll just refer to that.

1 Like

It’s … both. Thanks!

You’re using the wrong equality operator. Try it again with === and you’ll be doing it the right way.

Why would that be the right way? I mean, when I use variables, I mostly care about their values, not the addresses of those values

Because === computes “programmatic indistinguishability” which is the one true notion of object equality. Everything else is somewhat arbitrary and happens to be convenient sometimes and wrong other times.

http://home.pipeline.com/~hbaker1/ObjectIdentity.html