# Access field of custom struct by user-provided name

**URL:** <https://discourse.julialang.org/t/access-field-of-custom-struct-by-user-provided-name/85546>\
**Category:** General Usage\
**Created:** [August 9, 2022, 6:44pm UTC](https://discourse.julialang.org/t/access-field-of-custom-struct-by-user-provided-name/85546 "2022-08-09T18:44:59Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [August 9, 2022, 6:44pm UTC](https://discourse.julialang.org/t/access-field-of-custom-struct-by-user-provided-name/85546/1 "2022-08-09T18:44:59Z")

</div>

Suppose I want a `struct` that has to store a variable which can be quite general. Most typically, it will contain an array of `forces`, or alternatively an `energy` value. Something like:

```julia
struct System{T}
    property::T
end

```

The user initializes the `system` with:

```julia
forces = zeros(10)
system = System(forces)

```

That is fine, and now he/she can access the forces using…

```julia
system.property

```

Is there a way to overload `getproperty` in such a way that the user is able to retrieve the forces  
using

```julia
system.forces

```

?

Note that he/she could also have started with:

```julia
energy = 0.0
system = System(energy)

```

And now I would like that `system.energy` retrieved the `system.property` value, as well.

(ps: If I need a macro for this - which obviously can do the trick, let it go, I prefer to avoid macros).

Edit:

The best I could do so far is to define an additinal field `property_name`, and use something like:

```julia
julia> struct System{T}
           property_name::Symbol
           property::T
       end

julia> function Base.getproperty(s::System, a::Symbol) 
           if a == getfield(s, :property_name) 
               return getfield(s, :property)
           else
               return getfield(s, a)
           end
       end

julia> s = System(:energy, 0.0)
System{Float64}(:energy, 0.0)

julia> s.energy
0.0

```

Not too bad, but somewhat redundant. I guess I won’t be able to do that better without a macro, as no function will be able to access the name of the incoming variable.

---

<div class="post-metadata">

**Author:** ![RobertGregg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/robertgregg/32/22105_2.png) [@RobertGregg](https://discourse.julialang.org/u/RobertGregg)\
**Post date:** [August 9, 2022, 7:13pm UTC](https://discourse.julialang.org/t/access-field-of-custom-struct-by-user-provided-name/85546/2 "2022-08-09T19:13:36Z")

</div>

Without a macro I don’t think you can get the name of a variable that was passed into a function. However, you could do something like this:

```julia
struct System{T}
    propertyName::Symbol
    property::T
end

system1 = System(:forces, zeros(10))
system2 = System(:energy, 0.0)

#Set up a custom getproperty
Base.getproperty(sys::System, f::Symbol) = isequal(f, getfield(sys, :propertyName)) ? getfield(sys, :property) : error("type System has no field $(f)")

#These works
system1.forces
system2.energy

#But these do not work
system1.position
system1.property

```

If you still want to be able to access both `system1.forces` and `system1.property` you could add another condition to the `getproperty()` function or just settle with using `getfield(system1, :property)`.

Edit:

We seem to have come to the same conclusion 😅

---

<div class="post-metadata">

**Author:** ![digital\_carver](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/digital_carver/32/33818_2.png) [@digital\_carver](https://discourse.julialang.org/u/digital_carver)\
**Post date:** [August 9, 2022, 7:38pm UTC](https://discourse.julialang.org/t/access-field-of-custom-struct-by-user-provided-name/85546/3 "2022-08-09T19:38:14Z")

</div>

You can have a constructor that accepts keyword arguments, and have the user call it as `System(; forces)`.

```julia
julia> function System(; kwargs...)
         p = only(kwargs)
         p.first in (:forces, :energy) || throw(ArgumentError("Unknown keyword argument $(p.first)"))
         @eval function Base.getproperty(s::System, a::Symbol)
           if a == $p.first
             getfield(s, :property)
           else
             getfield(s, a)
           end
         end
         System(p.second)
       end
System

julia> system = System(; forces)
System{Vector{Float64}}([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])

julia> system.forces
10-element Vector{Float64}:
...

```

`System(; forces)` is effectively equivalent to `System(; forces = forces)`, so it’s a nice shortcut to get both the variable name and the value.

A disadvantage is that now `getproperty` lives inside this constructor which is a bit weird - but if you’re not using `System`’s `getproperty` for anything else, it’s not too bad.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [August 9, 2022, 7:54pm UTC](https://discourse.julialang.org/t/access-field-of-custom-struct-by-user-provided-name/85546/4 "2022-08-09T19:54:02Z")

</div>

Interesting idea, although I think we should avoid using `@eval`. For now the optional name field seems a safer solution (and I do need to access the fields by the original name).

---

<div class="post-metadata">

**Author:** ![rveltz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rveltz/32/2707_2.png) [@rveltz](https://discourse.julialang.org/u/rveltz)\
**Post date:** [August 9, 2022, 9:17pm UTC](https://discourse.julialang.org/t/access-field-of-custom-struct-by-user-provided-name/85546/5 "2022-08-09T21:17:33Z")

</div>

Define a type Energy and a type Forces like

```julia
forces = Forces(zeros(10))
system = System(forces)

```

And use dispatch

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [August 10, 2022, 5:42pm UTC](https://discourse.julialang.org/t/access-field-of-custom-struct-by-user-provided-name/85546/6 "2022-08-10T17:42:42Z")

</div>

Energy and Forces are examples, the data can be anything, actually. It would be on the user’s side to implement that custom type and dispatch.

---

<div class="post-metadata">

**Author:** ![\_bernhard](https://avatars.discourse-cdn.com/v4/letter/_/bc79bd/32.png) [@\_bernhard](https://discourse.julialang.org/u/_bernhard)\
**Post date:** [August 10, 2022, 8:06pm UTC](https://discourse.julialang.org/t/access-field-of-custom-struct-by-user-provided-name/85546/7 "2022-08-10T20:06:26Z")

</div>

It seems that, if you combine the techniques from above with your own you arrive at a solution that pretty much does what you want, while avoiding the redundancy of separately specifying the property name (provided you don’t mind storing the name in an extra field). I’m afraid, that it will always be either storing the name explicitly, using `eval` or using a macro.

```julia
struct System{T}
    property_name::Symbol
    property::T
end

function System(; prop...)
    name, value = only(prop)
    return System(name, value)
end

function Base.getproperty(s::System, a::Symbol)
    a == getfield(s, :property_name) && return getfield(s, :property)
    return getfield(s, a)
end

energy = 1e6
velocity = [1e1, 2e2, 3e3]

sys1 = System(; energy)
@assert sys1.energy == sys1.property

sys2 = System(; velocity)
@assert sys2.velocity == sys2.property

I hope this helps!

```

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [August 10, 2022, 8:17pm UTC](https://discourse.julialang.org/t/access-field-of-custom-struct-by-user-provided-name/85546/8 "2022-08-10T20:17:19Z")

</div>

> [@\_bernhard](#):
>
> ` name, value = only(prop)`

That is interesting, and may be useful to create what I want (I cannot use it directly because the `System` struct has other fields).

But what is the magic with this `name, value = only(prop)`? I cannot make that command work outside the specific context of the struct. Is that documented?

---

<div class="post-metadata">

**Author:** ![\_bernhard](https://avatars.discourse-cdn.com/v4/letter/_/bc79bd/32.png) [@\_bernhard](https://discourse.julialang.org/u/_bernhard)\
**Post date:** [August 10, 2022, 8:45pm UTC](https://discourse.julialang.org/t/access-field-of-custom-struct-by-user-provided-name/85546/9 "2022-08-10T20:45:16Z")

</div>

I am not 100% sure I understand your question, there is no magic involved. `only` gives you the only element of a collection, if there are more than one, it throws an exception. And since the one element is a `Pair` (`:key => value`) you can destructure it like `k,v = :a=>1` .

But if you change your struct according to

```julia
struct System{T}
    property_name::Symbol
    property::T
    additional_field::Int
end

function System(add_field; prop...)
    name, value = only(prop)
    return System(name, value, add_field)
end

```

it should work the same.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [August 10, 2022, 10:41pm UTC](https://discourse.julialang.org/t/access-field-of-custom-struct-by-user-provided-name/85546/10 "2022-08-10T22:41:04Z")

</div>

Oh, I see, the magic is this one:

```julia
julia> f(;p...) = @show p
f (generic function with 1 method)

julia> x = rand(2);

julia> f(;a = x, b = 2.0)
p = Base.Pairs{Symbol, Any, Tuple{Symbol, Symbol}, NamedTuple{(:a, :b), Tuple{Vector{Float64}, Float64}}}(:a => [0.2648247366377978, 0.8191610433834756], :b => 2.0)
pairs(::NamedTuple) with 2 entries:
  :a => [0.264825, 0.819161]
  :b => 2.0

julia> f(;x)
p = Base.Pairs(:x => [0.2648247366377978, 0.8191610433834756])
pairs(::NamedTuple) with 1 entry:
  :x => [0.264825, 0.819161]

```

When the keyword parameters are not pairs, the symbol of the variable is known by the function, but it isn’t when actual pairs are provided.

Maybe I can use that, yes, not sure if it will be clearer to the user than just explicitly give the name of the property as an independent parameter. Nice thing to learn, anyway, thanks.

---

<div class="post-metadata">

**Author:** ![\_bernhard](https://avatars.discourse-cdn.com/v4/letter/_/bc79bd/32.png) [@\_bernhard](https://discourse.julialang.org/u/_bernhard)\
**Post date:** [August 11, 2022, 6:03am UTC](https://discourse.julialang.org/t/access-field-of-custom-struct-by-user-provided-name/85546/11 "2022-08-11T06:03:41Z")

</div>

Yes, concerning your last example it is equivalent to write `f(; x)` and `f(; x=x)`.

So the following would also work:

```julia
en=1e6

sys = System(; energy=en)

@assert sys.property == sys.energy

```
