# Parametric Field Names

**URL:** <https://discourse.julialang.org/t/parametric-field-names/56428>\
**Category:** General Usage\
**Created:** [March 3, 2021, 6:03pm UTC](https://discourse.julialang.org/t/parametric-field-names/56428 "2021-03-03T18:03:27Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![dariush-bahrami](https://avatars.discourse-cdn.com/v4/letter/d/f1d935/32.png) [@dariush-bahrami](https://discourse.julialang.org/u/dariush-bahrami)\
**Post date:** [March 3, 2021, 6:03pm UTC](https://discourse.julialang.org/t/parametric-field-names/56428/1 "2021-03-03T18:03:27Z")

</div>

Consider Following Situation:

_I want to model an object with `struct` in Julia. I want this object fields be mutable. The goal is that when we change one of the fields, the rest of the fields will change automatically._

To define a specific problem, consider a dummy structure `Square`, The field names are: `side_length` and `area`. I want when I Change `side_length` the `area` changes automaticly. _I know this is not great example for real world use cases_

The following Code is definition of this structure:

```julia
mutable struct Square
    side
    area
end

s1 = Square(2, 4)

s1.side = 5

println(s1.area) # Obviously the output is 4

```

I am also curious to know if it is possible for some fields to be made automatically at the time of instantiation? for example at the creation time we only specify the `side_length` of this structure.

---

<div class="post-metadata">

**Author:** ![nilshg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nilshg/32/2283_2.png) [@nilshg](https://discourse.julialang.org/u/nilshg)\
**Post date:** [March 3, 2021, 6:07pm UTC](https://discourse.julialang.org/t/parametric-field-names/56428/2 "2021-03-03T18:07:28Z")

</div>

Your first question is not easily answered, although I think there are ways to achieve this.

The second question is simple, just define a constructor:

```julia
julia> mutable struct Square
           side
           area
       end

julia> Square(side) = Square(side, side^2)
Square

julia> Square(5)
Square(5, 25)

```

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [March 3, 2021, 6:11pm UTC](https://discourse.julialang.org/t/parametric-field-names/56428/3 "2021-03-03T18:11:41Z")

</div>

> [@dariush-bahrami](#):
>
> I am also curious to know if it is possible for some fields to be made automatically at the time of instantiation?

[https://docs.julialang.org/en/v1/manual/constructors/#man-inner-constructor-methods](https://docs.julialang.org/en/v1/manual/constructors/#man-inner-constructor-methods)

The inner constructor is what you use for this kind of things:

> It is good practice to provide as few inner constructor methods as possible: only those taking all arguments explicitly and enforcing essential error checking and transformation.

your example falls under “enforcing essential transformation”

* * *

```julia
julia> mutable struct Square
           side
           area
       Square(s) = new(s, s^2)
       end

julia> Square(3)
Square(3, 9)

```

In this case, we can even deliberately disallow the 2-argument constructor because the info is redundent. (assuming it’s useful for `Square` to carry an `.area` field

---

<div class="post-metadata">

**Author:** ![pdeffebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pdeffebach/32/10320_2.png) [@pdeffebach](https://discourse.julialang.org/u/pdeffebach)\
**Post date:** [March 3, 2021, 6:13pm UTC](https://discourse.julialang.org/t/parametric-field-names/56428/4 "2021-03-03T18:13:57Z")

</div>

I don’t think you will be able to override `Base.setproperty!` with this kind of behavior. I just tried it and ended up in a nest of StackOverflow errors.

Best to do a `changesidelength!(x)` method which does both steps.

---

<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:** [March 3, 2021, 6:14pm UTC](https://discourse.julialang.org/t/parametric-field-names/56428/5 "2021-03-03T18:14:40Z")

</div>

You could perhaps accomplish your first goal by making use of either set methods or making the struct fields `Observable` using Observables.jl and attach the recalculation behavior to the observable callback.

---

<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:** [March 3, 2021, 6:15pm UTC](https://discourse.julialang.org/t/parametric-field-names/56428/6 "2021-03-03T18:15:32Z")

</div>

What if you implement setproperty using setfield rather than recursively calling setproperty?

---

<div class="post-metadata">

**Author:** ![haberdashPI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/haberdashpi/32/26337_2.png) [@haberdashPI](https://discourse.julialang.org/u/haberdashPI)\
**Post date:** [March 3, 2021, 6:26pm UTC](https://discourse.julialang.org/t/parametric-field-names/56428/7 "2021-03-03T18:26:27Z")

</div>

Seems like `setproperty!` is the way to go (using `setfield!` internally to avoid the stack-overflow).

E.g.

```julia
mutable struct Square
   side
   area
end
function Base.setproperty!(x::Square, field::Symbol, val)
  if field == :side
    setfield!(x, :side, val)
    setfield!(x, :area, val^2)
  else
    # .. or whatever else you want to do here
    error("oops!")
  end
end

s1 = Square(2,4)
s1.side = 5
println(s1.area)
# output is 25

```

Alternatively, you could define a set of “derrived” properties that have no fields in the struct, and override `propertynames` and `getproperty` and use those to generate the derived properties.

---

<div class="post-metadata">

**Author:** ![Skoffer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skoffer/32/378_2.png) [@Skoffer](https://discourse.julialang.org/u/Skoffer)\
**Post date:** [March 3, 2021, 6:26pm UTC](https://discourse.julialang.org/t/parametric-field-names/56428/8 "2021-03-03T18:26:45Z")

</div>

Why should it be inner constructor?

```julia
julia> mutable struct Square
           side
           area
       end

julia> Square(side) = Square(side, side^2)
julia> Square(3)
Square(3, 9)

```

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [March 3, 2021, 6:27pm UTC](https://discourse.julialang.org/t/parametric-field-names/56428/9 "2021-03-03T18:27:33Z")

</div>

in your code here, try `Square(3, 10)`. Now you have an illegal instance

---

<div class="post-metadata">

**Author:** ![Skoffer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skoffer/32/378_2.png) [@Skoffer](https://discourse.julialang.org/u/Skoffer)\
**Post date:** [March 3, 2021, 6:29pm UTC](https://discourse.julialang.org/t/parametric-field-names/56428/10 "2021-03-03T18:29:11Z")

</div>

Ah, you mean if someone want to lock users out from instantiating some fields directly? Yes, it makes sense than.

One should override `area` field also, so it can be accessed read only.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [March 3, 2021, 6:32pm UTC](https://discourse.julialang.org/t/parametric-field-names/56428/11 "2021-03-03T18:32:20Z")

</div>

> [@Skoffer](#):
>
> One should override `area` field also, so it can be accessed read only.

How would you implement a `setside!(s::Sqaure, len)` if you do this? also you can’t make something truly read-only anyways, just don’t bother. If someone insists, they can break Julia itself easily.

---

<div class="post-metadata">

**Author:** ![Skoffer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skoffer/32/378_2.png) [@Skoffer](https://discourse.julialang.org/u/Skoffer)\
**Post date:** [March 3, 2021, 6:37pm UTC](https://discourse.julialang.org/t/parametric-field-names/56428/12 "2021-03-03T18:37:12Z")

</div>

Yes, you are right again. But in this case inner constructor is not providing real protection, so it’s ok to use outer constructor.

```julia
s = Square(3)
s.area = 10

```

Just two lines instead of one. Hardly worth inner constructor (especially taking into account that in order to change it one needs to restart REPL).

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [March 3, 2021, 6:41pm UTC](https://discourse.julialang.org/t/parametric-field-names/56428/13 "2021-03-03T18:41:35Z")

</div>

> [@Skoffer](#):
>
> `s.area = 10`

User should know not to do this. In some class-based OOP, this is “protected” by making `s.area` a “private” variable and `s.get_area()` to be “read-only”. But in the end of the day it only increase development overhead. You have to trust user not to deliberately digging holes for themselves at some point anyway.

---

<div class="post-metadata">

**Author:** ![pdeffebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pdeffebach/32/10320_2.png) [@pdeffebach](https://discourse.julialang.org/u/pdeffebach)\
**Post date:** [March 3, 2021, 6:45pm UTC](https://discourse.julialang.org/t/parametric-field-names/56428/14 "2021-03-03T18:45:07Z")

</div>

DataFrames has checks for corrupted DataFrames. Before operations, it makes sure all vectors are the right size. OP could also implement this.

But really, @dariush-bahrami , just store the side-length and use helper functions to do all that stuff for you.

---

<div class="post-metadata">

**Author:** ![MatFi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/matfi/32/10002_2.png) [@MatFi](https://discourse.julialang.org/u/MatFi)\
**Post date:** [March 3, 2021, 8:18pm UTC](https://discourse.julialang.org/t/parametric-field-names/56428/15 "2021-03-03T20:18:24Z")

</div>

Personally I’am not a huge friend of storing redundant data, and you can avoid any illegal instance by just storing the essential information once. Found this originally [here](https://discourse.julialang.org/t/getproperty-decorations-inheritance-in-0-7/11237/3) and meanwhile using this quite extensively:

```julia
mutable struct Square
    side
end

# Acutally not strictly needed just for completeness
# see https://docs.julialang.org/en/v1/base/base/#Base.propertynames   
propertynames(p::Square,private=true) = begin
    fields = fieldnames(typeof(p))    
    (fields...,:area,:diagonal)
end

#Dispatch the gets
Base.getproperty(p::Square,n::Symbol) = getproperty(p::Square,Val{n}())
Base.getproperty(p::Square,::Val{S}) where {S} = getfield(p,S) #generic fallback
Base.getproperty(p::Square,::Val{:area}) = p.side^2
Base.getproperty(p::Square,::Val{:diagonal}) = √2*p.side

#Dispatch the sets
Base.setproperty!(p::Square,n::Symbol,x) = setproperty!(p,Val{n}(),x)
Base.setproperty!(p::Square,::Val{S},x) where {S} = setfield!(p,S,x) #generic fallback
Base.setproperty!(p::Square, ::Val{:area},x) = setfield!(p,:side,√x)
Base.setproperty!(p::Square, ::Val{:diagonal},x) = setfield!(p,:side,x/√2)

julia> s = Square(√2)
Square(1.4142135623730951)

julia> s = Square(√2)^C

julia> s.diagonal
2.0000000000000004

julia> s.area=4
4

julia> s.diagonal
2.8284271247461903

julia> 

```

It is also easier to maintain this way and you can easily add up more implicit properties without stressing your memory too much.

---

<div class="post-metadata">

**Author:** ![haberdashPI](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/haberdashpi/32/26337_2.png) [@haberdashPI](https://discourse.julialang.org/u/haberdashPI)\
**Post date:** [March 3, 2021, 8:47pm UTC](https://discourse.julialang.org/t/parametric-field-names/56428/16 "2021-03-03T20:47:58Z")

</div>

I agree that can make a lot of sense. That was the reason for the “Alternatively, you could define a set of “derrived” properties that have no fields in the struct, and override `propertynames` and `getproperty` and use those to generate the derived properties.” part of my comment.

I think which route you go—the `setproperty!` or the `getproperty` route—depends a lot on the exact tradeoffs of the problem. That is, do you care more about memory or compute complexity for the actual problem you want to solve.

---

<div class="post-metadata">

**Author:** ![dariush-bahrami](https://avatars.discourse-cdn.com/v4/letter/d/f1d935/32.png) [@dariush-bahrami](https://discourse.julialang.org/u/dariush-bahrami)\
**Post date:** [March 3, 2021, 10:56pm UTC](https://discourse.julialang.org/t/parametric-field-names/56428/17 "2021-03-03T22:56:32Z")

</div>

Thank you very much. This solution seems to be the most straightforward.
