# Why can't I use hcat in a for-loop?

**URL:** <https://discourse.julialang.org/t/why-cant-i-use-hcat-in-a-for-loop/125935>\
**Category:** General Usage\
**Tags:** dataframes\
**Created:** [February 15, 2025, 10:17am UTC](https://discourse.julialang.org/t/why-cant-i-use-hcat-in-a-for-loop/125935 "2025-02-15T10:17:37Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![Xu\_Shan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/xu_shan/32/214900_2.png) [@Xu\_Shan](https://discourse.julialang.org/u/Xu_Shan)\
**Post date:** [February 15, 2025, 10:17am UTC](https://discourse.julialang.org/t/why-cant-i-use-hcat-in-a-for-loop/125935/1 "2025-02-15T10:17:37Z")

</div>

Hi guys,  
I am trying to concatenate rows into an empty dataframe using a for-loop like this:

```julia
sensitivity_mean_df = DataFrame()
base_df = DataFrame()
for variable in variables
    if isempty(base_df)
        base_df = DataFrame(parameter=unique_parameters)
    end
    sensitivity_mean_df = hcat(sensitivity_mean_df, some_dataset, makeunique=true)
end

```

However, if I run the code, I was told:

```julia
ERROR: UndefVarError: `base_df` not defined

```

even if I comment lines about base\_df, then I got error

```julia
ERROR: UndefVarError: `sensitivity_mean_df` not defined

```

Why is that?

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [February 15, 2025, 10:20am UTC](https://discourse.julialang.org/t/why-cant-i-use-hcat-in-a-for-loop/125935/2 "2025-02-15T10:20:40Z")

</div>

You need to say `global base_df` inside the for loop if you’re in global scope? The issue would then go away of you place this code inside a function

---

<div class="post-metadata">

**Author:** ![Xu\_Shan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/xu_shan/32/214900_2.png) [@Xu\_Shan](https://discourse.julialang.org/u/Xu_Shan)\
**Post date:** [February 15, 2025, 10:21am UTC](https://discourse.julialang.org/t/why-cant-i-use-hcat-in-a-for-loop/125935/3 "2025-02-15T10:21:56Z")

</div>

thanks! but why? if I use python, I could directly do such things without declare the global…

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [February 15, 2025, 10:49am UTC](https://discourse.julialang.org/t/why-cant-i-use-hcat-in-a-for-loop/125935/4 "2025-02-15T10:49:58Z")

</div>

This is not Python so you can’t generally expect everything to behave exactly the same, the for loop introduces its own scope here.

Generally, it’s best practice to place code in functions for good performance, and you would not have this issue.

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [February 15, 2025, 11:16am UTC](https://discourse.julialang.org/t/why-cant-i-use-hcat-in-a-for-loop/125935/5 "2025-02-15T11:16:30Z")

</div>

@Xu_Shan you can avoid manual loops and use a higher-level construct to reduce a list of dataframes with `hcat`.

```julia
dfs = [DataFrame(...), DataFrame(...), DataFrame(...)]

f(df1, df2) = hcat(df1, df2, makeunique=true)

df = reduce(f, dfs)

```

---

<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:** [February 15, 2025, 11:16am UTC](https://discourse.julialang.org/t/why-cant-i-use-hcat-in-a-for-loop/125935/6 "2025-02-15T11:16:42Z")

</div>

Also worth pointing out that this would work in interactive contexts like the REPL and Jupyter notebooks because they relax the global scope rules a little for soft scopes. However, in source code or expressions, `base_df = ...` implicitly declared that `base_df` is a local variable in the for loop, so when you try to access it earlier in `isempty(base_df)`, it was actually an undefined local variable.

> [@Xu\_Shan](#):
>
> but why?

The reason why local scopes like for loops automatically reassign outer local variables but not global variables is because global scopes can easily get very large. With `include`, you can split one global scope into arbitrarily many files, and you can `eval` any number of further expressions into it. This rule guards against accidental reassignment of global variables and encourages more local scopes, which _can’t_ be split across multiple files or expressions.

> [@Xu\_Shan](#):
>
> if I use python, I could directly do such things without declare the global…

Note that Python makes every file its own module. That pushes people toward many more smaller modules they have to import variables between, but it’s safer for more blocks to not introduce local scope. On the other hand, Python’s few locally scoped blocks don’t share variables automatically when nested, needing `nonlocal` declarations. Different languages have different designs and thus different rules, we just have to adjust.

---

<div class="post-metadata">

**Author:** ![Xu\_Shan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/xu_shan/32/214900_2.png) [@Xu\_Shan](https://discourse.julialang.org/u/Xu_Shan)\
**Post date:** [February 15, 2025, 2:53pm UTC](https://discourse.julialang.org/t/why-cant-i-use-hcat-in-a-for-loop/125935/7 "2025-02-15T14:53:35Z")

</div>

thanks! Then how can we use something like below?

```julia
n = 0
while something
  n += 1
end

```

---

<div class="post-metadata">

**Author:** ![ArchieCall](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/archiecall/32/206_2.png) [@ArchieCall](https://discourse.julialang.org/u/ArchieCall)\
**Post date:** [February 15, 2025, 3:53pm UTC](https://discourse.julialang.org/t/why-cant-i-use-hcat-in-a-for-loop/125935/8 "2025-02-15T15:53:36Z")

</div>

Wrap it in function like so:

```julia
function main()
    n = 0
    while n < 10
        n += 1
    end
    @show(n)
end
main()

```

---

<div class="post-metadata">

**Author:** ![Xu\_Shan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/xu_shan/32/214900_2.png) [@Xu\_Shan](https://discourse.julialang.org/u/Xu_Shan)\
**Post date:** [February 15, 2025, 4:00pm UTC](https://discourse.julialang.org/t/why-cant-i-use-hcat-in-a-for-loop/125935/9 "2025-02-15T16:00:19Z")

</div>

thanks! So within a function, it’s not a global variable anymore? but even it is local variable, they are within difference scopes?

---

<div class="post-metadata">

**Author:** ![eldee](https://avatars.discourse-cdn.com/v4/letter/e/b5a626/32.png) [@eldee](https://discourse.julialang.org/u/eldee)\
**Post date:** [February 15, 2025, 4:10pm UTC](https://discourse.julialang.org/t/why-cant-i-use-hcat-in-a-for-loop/125935/10 "2025-02-15T16:10:21Z")

</div>

Check out the documentation on the scoping rules: [Scope of Variables · The Julia Language](https://docs.julialang.org/en/v1/manual/variables-and-scoping/)

As an example, consider

```julia
n = 0
while rand() < 0.9
	n += 1
end
println(n)

```

When run in the REPL, this works as intended (cf. @Benny 's reply):

```julia-repl
julia> n = 0

julia> while rand() < 0.9
	       n += 1
       end

julia> println(n)
18

```

If you put it in a file called script.jl, then running `julia script.jl` in the terminal (or `include("script.jl")` in the Julia REPL) yields

```julia
> julia script.jl
┌ Warning: Assignment to `n` in soft scope is ambiguous because a global variable by the same name exists: `n` will be treated as a new local. Disambiguate by using `local n` to suppress this warning or `global n` to assign to the existing global variable.
└ @ (...)\script.jl:3
ERROR: LoadError: UndefVarError: `n` not defined in local scope
Suggestion: check for an assignment to a local variable that shadows a global of the same name.
Stacktrace:
 ...

```

The warning hints that

```julia
n = 0
while rand() < 0.9
    global n
    n += 1
end
println(n)

```

in script.jl will solve the problem, as it indeed does:

```julia
> julia script.jl
8

```

In most situations the best solution (also for performance) is just to avoid (non-typed / non-`const`) global variables entirely, e.g. by using a function (cf. @ArchieCall ). If you put

```julia
function main()
	n = 0
	while rand() < 0.9
		n += 1
	end
	println(n)
end

main()

```

in our script.jl, you get

```julia-repl
julia> include("script.jl")
4

```

This also works in the REPL:

```julia-repl
julia> function f()
           n = 0
           while rand() < 0.9
               n += 1
           end
           println(n)
       end
f (generic function with 1 method)

julia> f()
8

```

If you had previously defined a global variable called `n`, then that is completely unrelated to the local `n` inside `f`:

```julia-repl
julia> n 
18

```
