# Evaluate a local variable by name

**URL:** <https://discourse.julialang.org/t/evaluate-a-local-variable-by-name/129846>\
**Category:** New to Julia\
**Created:** [June 12, 2025, 8:31pm UTC](https://discourse.julialang.org/t/evaluate-a-local-variable-by-name/129846 "2025-06-12T20:31:10Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)\
**Post date:** [June 12, 2025, 8:31pm UTC](https://discourse.julialang.org/t/evaluate-a-local-variable-by-name/129846/1 "2025-06-12T20:31:10Z")

</div>

Is there a particularly elegant way to `eval` a _local_ variable? My use case would be this function:

```julia
function A_dipole(which, x, y, z; A₀=19.8517061694#=Å³ MHz=#)
	i, j = (Symbol(_) for _ in String(which))
	r = √(x^2 + y^2 + z^2)
	return A₀ * (1/r^3 - 3*eval(i)*eval(j)/r^5)
end

```

where for, e.g. `A_dipole(:xy, x, y, z)`, the `eval(i)` would evaluate to the value of `x` and `eval(j)` would evaluate to the value of `y`. I can of course define `r_i` and `r_j` values like

```julia
function A_dipole(which, x, y, z; A₀=19.8517061694#=Å³ MHz=#)
	i, j = (Symbol(_) for _ in String(which))
	r_i = (i == :x) ? x : (i == :y) ? y : (i == :z) ? z : 0.0
	r_j = (j == :x) ? x : (j == :y) ? y : (j == :z) ? z : 0.0
	r = √(x^2 + y^2 + z^2)
	return A₀ * (1/r^3 - 3*r_i*r_j/r^5)
end

```

but I was wondering if Julia provided any neat way that I’m not aware of to evaluate local variables more directly.

---

<div class="post-metadata">

**Author:** ![JonasWickman](https://avatars.discourse-cdn.com/v4/letter/j/9de0a6/32.png) [@JonasWickman](https://discourse.julialang.org/u/JonasWickman)\
**Post date:** [June 12, 2025, 8:46pm UTC](https://discourse.julialang.org/t/evaluate-a-local-variable-by-name/129846/2 "2025-06-12T20:46:49Z")

</div>

Maybe something like this is a bit cleaner?

```julia
function A_dipole(which, x, y, z)
    v = (; x, y, z)
    i, j = (Symbol(_) for _ in String(which))
    r_i = getproperty(v, i)
    r_j = getproperty(v, j)
    ...
end

```

If you changed `which` to be `(:x,:y)`, that would make the string conversion unnecessary as well, but I gather that being able to send in e.g., `:xy` is the whole point of the exercise.

Edit: some more messing around with named tuples:

```julia
coord_nt() = (;
    xy = (:x, :y),
    xz = (:x, :z),
    yx = (:y, :x),
    yz = (:y, :z),
    zx = (:z, :x),
    zy = (:z, :y)
)

function A_dipole(which, x, y, z)
    v = (; x, y, z)
    i, j = getproperty(coord_nt(), which)
    r_i = getproperty(v, i)
    r_j = getproperty(v, j)
    return r_i, r_j
end

```

This one is at least type stable, so it’s got that going for it.

---

<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:** [June 12, 2025, 11:05pm UTC](https://discourse.julialang.org/t/evaluate-a-local-variable-by-name/129846/3 "2025-06-12T23:05:57Z")

</div>

> [@goerz](#):
>
> `eval` a _local_ variable

`eval` can do a lot more than retrieve variables, and doing any of that in a local scope prevents method optimization. If you want the runtime state of variables in a local scope, then `(Base.@locals)` makes a `Dict{Symbol, Any}`. That is obviously not type stable, so leverage any restrictions on type or number like the above.

Your example is symmetric enough that I would normally just reorder arguments to accomplish the same thing, but I imagine you can’t do that in your actual code.

---

<div class="post-metadata">

**Author:** ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)\
**Post date:** [June 13, 2025, 3:37am UTC](https://discourse.julialang.org/t/evaluate-a-local-variable-by-name/129846/4 "2025-06-13T03:37:01Z")

</div>

> [@JonasWickman](#):
>
> Maybe something like this is a bit cleaner?

Yes, that’s great! And `v[i]` instead of `getproperty(v, i)` works just fine. So I ended up with

```julia
function A_dipole(which, x, y, z; A₀=19.8517061694#=Å³ MHz=#)
	i, j = (Symbol(_) for _ in String(which))
	r_ = (; x, y, z)
	r = @. √(x^2 + y^2 + z^2)
	return @. A₀ * (1 / r^3 - 3 * r_[i] * r_[j] / r^5)
end

```

That’s augmented with `@.`, since it had to work on vectors as well as scalars, and then allows me to do `A_dipole(:xx, df[:, "x (Å)"], df[:, "y (Å)"], df[:, "z (Å)"])` for a [dataframe containing some data for C13 lattice sites w.r.t to an NV center in diamond](https://ivadygroup.elte.hu/hyperfine/nv/index.html).

> If you changed `which` to be `(:x,:y)`, that would make the string conversion unnecessary as well

Yeah, I was a little miffed at the String-Symbol roundtripping, but according to BenchmarkTools, the version with `(:x, :y)` isn’t any faster

> but I gather that being able to send in e.g., `:xy` is the whole point of the exercise.

This is just a function I’m writing for myself in a notebook, so this can be whatever I feel like typing. But yeah, `A_dipole(:xy, x, y, z)` seemed nicer.

> [@Benny](#):
>
> If you want the runtime state of variables in a local scope, then `(Base.@locals)` makes a `Dict{Symbol, Any}`

That’s technically the answer to my question, even though using a NamedTuple seems by far the more elegant solution.

> [@Benny](#):
>
> Your example is symmetric enough that I would normally just reorder arguments to accomplish the same thing, but I imagine you can’t do that in your actual code.

This is my actual code 😉 . But like I said, this is just a function in a notebook I’m writing for myself, so the aim was probably “elegance” over most other (e.g., performance) concerns. Just a bit of curiosity to learn about `Base.@locals` (which I wasn’t aware of), and to be reminded of the existence of NamedTuples (which I tend to forget).

---

<div class="post-metadata">

**Author:** ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)\
**Post date:** [June 13, 2025, 8:34am UTC](https://discourse.julialang.org/t/evaluate-a-local-variable-by-name/129846/5 "2025-06-13T08:34:40Z")

</div>

> [@goerz](#):
>
> `r = @. √(x^2 + y^2 + z^2)`

Just a minor note: Whenever you write something like this consider using `hypot` instead. It protects you against over-/underflows and is shorter to type:  
`r = hypot.(x, y, z)`
