# Redefining print method changes variable scoping in loop

**URL:** <https://discourse.julialang.org/t/redefining-print-method-changes-variable-scoping-in-loop/108010>\
**Category:** Internals & Design\
**Tags:** scope, show, for-loop\
**Created:** [December 24, 2023, 4:57pm UTC](https://discourse.julialang.org/t/redefining-print-method-changes-variable-scoping-in-loop/108010 "2023-12-24T16:57:52Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![Tetrakai](https://avatars.discourse-cdn.com/v4/letter/t/4da419/32.png) [@Tetrakai](https://discourse.julialang.org/u/Tetrakai)\
**Post date:** [December 24, 2023, 4:57pm UTC](https://discourse.julialang.org/t/redefining-print-method-changes-variable-scoping-in-loop/108010/1 "2023-12-24T16:57:52Z")

</div>

Why does the first loop work but the second does not?

The MWE:

> **Summary**
>
> ```julia
> using Printf
> for n in 1:10
> if n == 1
> flag = true
> idx_last = 1
> else
> flag = false
> idx_last = ifelse(flag, n, idx_last)
> end
> 
> # Print Progress
> Base.show(io::IO, f::Float64) = @printf(io, "%.2f", f)
> end
> 
> for n in 1:10
> if n == 1
> flag = true
> idx_last = 1
> else
> flag = false
> idx_last = ifelse(flag, n, idx_last)
> end
> 
> # Print Progress
> # Base.show(io::IO, f::Float64) = @printf(io, "%.2f", f)
> end
> 
> ```

I get:

```julia
julia> using Printf

julia> for n in 1:10
               if n == 1
                       flag = true
                       idx_last = 1
               else
                       flag = false
                       idx_last = ifelse(flag, n, idx_last)
               end
       
           # Print Progress
               Base.show(io::IO, f::Float64) = @printf(io, "%.2f", f)
       end

julia> for n in 1:10
               if n == 1
                       flag = true
                       idx_last = 1
               else
                       flag = false
                       idx_last = ifelse(flag, n, idx_last)
               end
       
           # Print Progress
               # Base.show(io::IO, f::Float64) = @printf(io, "%.2f", f)
       end
ERROR: UndefVarError: `idx_last` not defined
Stacktrace:
 [1] top-level scope
   @ ./REPL[3]:7

```

---

<div class="post-metadata">

**Author:** ![Tetrakai](https://avatars.discourse-cdn.com/v4/letter/t/4da419/32.png) [@Tetrakai](https://discourse.julialang.org/u/Tetrakai)\
**Post date:** [December 26, 2023, 3:18pm UTC](https://discourse.julialang.org/t/redefining-print-method-changes-variable-scoping-in-loop/108010/2 "2023-12-26T15:18:24Z")

</div>

Anyone have an idea why the first loop does work? My understanding from the docs is that ` idx_last` should not persist into the second iteration. But it does.

---

<div class="post-metadata">

**Author:** ![mike.ingold](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mike.ingold/32/203749_2.png) [@mike.ingold](https://discourse.julialang.org/u/mike.ingold)\
**Post date:** [December 26, 2023, 4:36pm UTC](https://discourse.julialang.org/t/redefining-print-method-changes-variable-scoping-in-loop/108010/3 "2023-12-26T16:36:54Z")

</div>

Attempting to reproduce in two REPL’s each with clean temp environment (Julia v1.9.4).

The first version

```julia
(@v1.9) pkg> activate --temp
  Activating new project at `C:\Users\x\AppData\Local\Temp\jl_06Fn89`

julia> using Printf

julia> for n in 1:10
           if n == 1
               flag = true
               idx_last = 1
           else
               flag = false
               idx_last = ifelse(flag, n, idx_last)
           end

           # Print Progress
           Base.show(io::IO, f::Float64) = @printf(io, "%.2f", f)
       end
ERROR: UndefVarError: `idx_last` not defined
Stacktrace:
 [1] top-level scope
   @ REPL[3]:7

```

and the second version

```julia
(@v1.9) pkg> activate --temp
  Activating new project at `C:\Users\x\AppData\Local\Temp\jl_DNYW0n`

julia> using Printf

julia> for n in 1:10
           if n == 1
               flag = true
               idx_last = 1
           else
               flag = false
               idx_last = ifelse(flag, n, idx_last)
           end

           # Print Progress
           # Base.show(io::IO, f::Float64) = @printf(io, "%.2f", f)
       end
ERROR: UndefVarError: `idx_last` not defined
Stacktrace:
 [1] top-level scope
   @ .\REPL[3]:7

```

---

<div class="post-metadata">

**Author:** ![mike.ingold](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mike.ingold/32/203749_2.png) [@mike.ingold](https://discourse.julialang.org/u/mike.ingold)\
**Post date:** [December 26, 2023, 4:40pm UTC](https://discourse.julialang.org/t/redefining-print-method-changes-variable-scoping-in-loop/108010/4 "2023-12-26T16:40:01Z")

</div>

What version of Julia are you using? I can’t reproduce your all-in-one-REPL example with the provided MWE because I get that error for the first loop.

---

<div class="post-metadata">

**Author:** ![Tetrakai](https://avatars.discourse-cdn.com/v4/letter/t/4da419/32.png) [@Tetrakai](https://discourse.julialang.org/u/Tetrakai)\
**Post date:** [December 26, 2023, 4:58pm UTC](https://discourse.julialang.org/t/redefining-print-method-changes-variable-scoping-in-loop/108010/5 "2023-12-26T16:58:47Z")

</div>

Thanks, I did try using fresh REPL sessions for each loop but not in a temp project.

I’m using version 1.10.0-rc2 and get the same results:

```julia
(@v1.10) pkg> activate --temp
  Activating new project at `/tmp/jl_sQfyMH`

julia> using Printf

julia> for n in 1:10
               if n == 1
                       flag = true
                       idx_last = 1
               else
                       flag = true
                       idx_last = ifelse(flag, n, idx_last)
               end
       
           # Print Progress
           Base.show(io::IO, f::Float64) = @printf(io, "%.2f", f)
           print(idx_last)
       end
12345678910

```

My versioninfo:

```julia
julia> versioninfo()
Julia Version 1.10.0-rc2
Commit dbb9c46795b (2023-12-03 15:25 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: 64 × AMD Ryzen Threadripper 2990WX 32-Core Processor
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-15.0.7 (ORCJIT, znver1)
  Threads: 1 on 64 virtual cores

```

It also runs using `julia --startup-file=no`. So not something in the startup.jl file it seems.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [December 26, 2023, 11:09pm UTC](https://discourse.julialang.org/t/redefining-print-method-changes-variable-scoping-in-loop/108010/6 "2023-12-26T23:09:41Z")

</div>

This seems like a version bug to me, I think it warrants opening an issue. I would leave out the `print(idx_last)` line if the problem reproduces without it, better to leave out cosmetic factors.

The only guess I have for `idx_last` persisting is if it somehow mistakenly assigned a global variable that disappears somehow? Pretty far-fetched, but you could throw in a `println(n, hasproperty(Main, :idx_last), isdefined(Main, :idx_last))` (first checks if global variable exists, second checks if it is assigned to a value) as the first line in the loop body?

---

<div class="post-metadata">

**Author:** ![Tetrakai](https://avatars.discourse-cdn.com/v4/letter/t/4da419/32.png) [@Tetrakai](https://discourse.julialang.org/u/Tetrakai)\
**Post date:** [December 28, 2023, 8:40pm UTC](https://discourse.julialang.org/t/redefining-print-method-changes-variable-scoping-in-loop/108010/7 "2023-12-28T20:40:08Z")

</div>

So I updated to 1.10.0. I got the same results, then added your line:

```julia
julia> using Printf

julia> for n in 1:10
            println(n, hasproperty(Main, :idx_last), isdefined(Main, :idx_last))
           if n == 1
               flag = true
               idx_last = 1
           else
               flag = false
               idx_last = ifelse(flag, n, idx_last)
           end

           # Print Progress
           Base.show(io::IO, f::Float64) = @printf(io, "%.2f", f)
       end
1falsefalse
2falsefalse
3falsefalse
4falsefalse
5falsefalse
6falsefalse
7falsefalse
8falsefalse
9falsefalse
10falsefalse

julia> for n in 1:10
           println(n, hasproperty(Main, :idx_last), isdefined(Main, :idx_last))
           if n == 1
               flag = true
               idx_last = 1
           else
               flag = false
               idx_last = ifelse(flag, n, idx_last)
           end

           # Print Progress
           # Base.show(io::IO, f::Float64) = @printf(io, "%.2f", f)
       end
1falsefalse
2falsefalse
ERROR: UndefVarError: `idx_last` not defined
Stacktrace:
 [1] top-level scope
   @ ./REPL[11]:8

```

It appears the second loop does iterate twice. Does anyone else see this in Julia 1.10?

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [December 28, 2023, 10:50pm UTC](https://discourse.julialang.org/t/redefining-print-method-changes-variable-scoping-in-loop/108010/8 "2023-12-28T22:50:43Z")

</div>

> [@Tetrakai](#):
>
> It appears the second loop does iterate twice.

It is supposed to, the first iteration goes to the unproblematic `n==1` branch, the second iteration goes to the `else` branch where it throws an error over the non-existent `idx_last` in `ifelse(flag, n, idx_last)`.

You demonstrated that it’s not a temporary global variable at least, so you should omit that `println` line in the MWE. You could mention that adding such a line would show the REPL’s global scope lacks `idx_last` at any point.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [January 5, 2024, 12:26pm UTC](https://discourse.julialang.org/t/redefining-print-method-changes-variable-scoping-in-loop/108010/9 "2024-01-05T12:26:47Z")

</div>

Still happens in the full 1.10.0 release, has an issue been opened on Github for this? BTW you don’t need to define `Base.show` in particular, even a local `foo() = 0` before or after the if statement will cause this.

---

<div class="post-metadata">

**Author:** ![Tetrakai](https://avatars.discourse-cdn.com/v4/letter/t/4da419/32.png) [@Tetrakai](https://discourse.julialang.org/u/Tetrakai)\
**Post date:** [January 5, 2024, 2:20pm UTC](https://discourse.julialang.org/t/redefining-print-method-changes-variable-scoping-in-loop/108010/10 "2024-01-05T14:20:18Z")

</div>

It got tagged as lowering/bug/parser:

> <https://github.com/JuliaLang/julia/issues/52664>
>
> I asked about this on the discourse and it was recommended I open an issue:
> htt…ps://discourse.julialang.org/t/redefining-print-method-changes-variable-scoping-in-loop/108010
> 
> Essentially the idx\_last variable persists when it should not. 
> \`\`\`
> using Printf
> for n in 1:10
> if n == 1
> flag = true
> idx\_last = 1
> else
> flag = true
> idx\_last = ifelse(flag, n, idx\_last)
> end
> Base.show(io::IO, f::Float64) = @printf(io, "%.2f", f)
> end
> 
> \`\`\`
> 
> If I comment out the Base.show() line then I \_correctly\_ see \`UndefVarError: idx\_last not defined\`.
> 
> This happened for me using versions 10.10.0-rc2 and 1.10.0. Apparently the expected behavior was seen using v1.9.4 on windows. Also, from the discourse you can see we verified \`idx\_last\` is never in the global scope. My versioninfo:
> 
> \`\`\`
> Julia Version 1.10.0
> Commit 3120989f39b (2023-12-25 18:01 UTC)
> Build Info:
> Official https://julialang.org/ release
> Platform Info:
> OS: Linux (x86\_64-linux-gnu)
> CPU: 64 × AMD Ryzen Threadripper 2990WX 32-Core Processor
> WORD\_SIZE: 64
> LIBM: libopenlibm
> LLVM: libLLVM-15.0.7 (ORCJIT, znver1)
> Threads: 1 on 64 virtual cores
> 
> \`\`\`
