# Doing trivial transformations and assertions inside a struct definition

**URL:** <https://discourse.julialang.org/t/doing-trivial-transformations-and-assertions-inside-a-struct-definition/61054>\
**Category:** New to Julia\
**Tags:** struct\
**Created:** [May 13, 2021, 12:00am UTC](https://discourse.julialang.org/t/doing-trivial-transformations-and-assertions-inside-a-struct-definition/61054 "2021-05-13T00:00:21Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![maxkapur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maxkapur/32/21208_2.png) [@maxkapur](https://discourse.julialang.org/u/maxkapur)\
**Post date:** [May 13, 2021, 12:00am UTC](https://discourse.julialang.org/t/doing-trivial-transformations-and-assertions-inside-a-struct-definition/61054/1 "2021-05-13T00:00:21Z")

</div>

I am defining a struct, and I would like to make it perform some trivial transformations on the input data to simplify later calculations.

The goal is for the struct to accept just a vector of `qualities` and `prices`, and then also be able to access the _normalized prices_ (that is, prices adjusted so they some to one) and some other transformations.

Here is what I am _trying_ to do:

```julia
struct Market
    qualities::Array{<:AbstractFloat, 1}
    prices::Array{<:AbstractFloat, 1}
    
    normalized_prices = prices / sum(prices)
end

```

Then calling

```julia
m = Market([.2, .2, .2], [1., 2., 2.])
m.normalized_prices

```

should yield the vector `[.2, .4, .4]`.

I would also be interested in normalizing the prices in-place, i.e. something like

```julia
struct Market
    qualities::Array{<:AbstractFloat, 1}
    prices::Array{<:AbstractFloat, 1}
    
    prices /= sum(prices)
end

```

However, both of the struct definitions above yield an error. I know that one way to do the second task is to redefine the function `Market(qualities, prices)` so that it does the normalization and then constructs the market, but is there a better way?

Separately, I would also like to assert that the input vectors are of the same length:

```julia
struct Market
    qualities::Array{<:AbstractFloat, 1}
    prices::Array{<:AbstractFloat, 1}
    
    @assert size(qualities) == size(prices)
end

```

How should I do this?

---

<div class="post-metadata">

**Author:** ![OlivierHnt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/olivierhnt/32/6227_2.png) [@OlivierHnt](https://discourse.julialang.org/u/OlivierHnt)\
**Post date:** [May 13, 2021, 12:19am UTC](https://discourse.julialang.org/t/doing-trivial-transformations-and-assertions-inside-a-struct-definition/61054/2 "2021-05-13T00:19:45Z")

</div>

I would probably define it as follows:

```nohighlight
struct Market{T<:AbstractFloat,S<:AbstractFloat}
    qualities::Array{T, 1}
    prices::Array{S, 1}
    function Market{T,S}(qualities::Array{T, 1}, prices::Array{S, 1}) where {T<:AbstractFloat,S<:AbstractFloat}
        # with the inner constructor we check and process the inputs
        length(qualities) == length(prices) || return throw(DimensionMismatch)
        prices ./= sum(prices)
        return new{T,S}(qualities, prices)
    end
end

# add a convenient outer constructor which calls the inner constructor
Market(qualities::Array{T, 1}, prices::Array{S, 1}) where {T<:AbstractFloat,S<:AbstractFloat} =
    Market{T,S}(qualities, prices)

```

Note that I added parametric types; if, for your needs, `T` and `S` are equal, then you should only put one. For more details, you can refer to the [Constructors](https://docs.julialang.org/en/v1/manual/constructors/) section of the manual.

Hope this helps 🙂

---

<div class="post-metadata">

**Author:** ![Iagoba\_Apellaniz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/iagoba_apellaniz/32/34406_2.png) [@Iagoba\_Apellaniz](https://discourse.julialang.org/u/Iagoba_Apellaniz)\
**Post date:** [May 13, 2021, 1:13am UTC](https://discourse.julialang.org/t/doing-trivial-transformations-and-assertions-inside-a-struct-definition/61054/3 "2021-05-13T01:13:20Z")

</div>

I think one could define `getproperty` as you can see in the documentation [Base.getproperty](https://docs.julialang.org/en/v1/base/base/#Base.getproperty). You have to import it first such that you can extend its definition with a new method. Note that it has to be defined outside the `struct`. Moreover, you can define it wherever you want, as long as it is before the first call (I think).

```julia
struct Market
    qualities
    prices
end

Base.getproperty(m::Market, :normalized_prices) = m.prices/sum(m.prices)

m = Market([1, 2], [2, 3])

m.normalized_prices # this sould give [0.4, 0.6]

```

May not be the solution, but I think it could help you to understand how `getproperty`/`setproperty` works.

---

<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:** [May 13, 2021, 1:21am UTC](https://discourse.julialang.org/t/doing-trivial-transformations-and-assertions-inside-a-struct-definition/61054/4 "2021-05-13T01:21:43Z")

</div>

> [@maxkapur](#):
>
> ```julia
> m = Market([.2, .2, .2], [1., 2., 2.])
> m.normalized_prices
> 
> ```

I think this is not what you should expect or do in Julia. Structures do not contain methods, and the way to obtain that is to use dispatch. Meaning, you should do:

```julia
julia> struct Market{T,S}
           qualities::Vector{T}  
           prices::Vector{S}
       end

julia> normalized_prices(x::Market) = x.prices / sum(x.prices)
normalized_prices (generic function with 1 method)

julia> x = Market([.2, .2, .2], [1., 2., 2.])
Market{Float64, Float64}([0.2, 0.2, 0.2], [1.0, 2.0, 2.0])

julia> normalized_prices(x)
3-element Vector{Float64}:
 0.2
 0.4
 0.4

```

That if you want to store the non-normalized prices and compute and retrieve the normalized prices when you want. If you want to store _only_ the normalized prices, than you should use the constructor suggested by @OlivierHnt

If you want to store in the struct _both_ the normalized and the non-normalized prices, you need an additional field, and then you can do:

```julia
julia> struct Market{T,S}
           qualities::Vector{T}  
           prices::Vector{S}
           normalized_prices::Vector{S}
       end

julia> Market(qualities,prices) = Market(qualities,prices,prices/sum(prices))
Market

julia> x = Market([.2, .2, .2], [1., 2., 2.])
Market{Float64, Float64}([0.2, 0.2, 0.2], [1.0, 2.0, 2.0], [0.2, 0.4, 0.4])

julia> x.normalized_prices
3-element Vector{Float64}:
 0.2
 0.4
 0.4

```

Which is a little bit simpler than the other constructor because there is no ambiguity in the instantiation with 2 or 3 parameters.

---

<div class="post-metadata">

**Author:** ![Iagoba\_Apellaniz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/iagoba_apellaniz/32/34406_2.png) [@Iagoba\_Apellaniz](https://discourse.julialang.org/u/Iagoba_Apellaniz)\
**Post date:** [May 13, 2021, 1:25am UTC](https://discourse.julialang.org/t/doing-trivial-transformations-and-assertions-inside-a-struct-definition/61054/5 "2021-05-13T01:25:05Z")

</div>

To store more that what you need is not usual. If one can avoid storing `normalized_prices` with the use of `getproperty` could be better I think. There could be special cases though 🙂.

---

<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:** [May 13, 2021, 1:33am UTC](https://discourse.julialang.org/t/doing-trivial-transformations-and-assertions-inside-a-struct-definition/61054/6 "2021-05-13T01:33:24Z")

</div>

Defining a `getproperty` for a symbol that does not correspond to a field is not usual either. For that what is natural is to define a function and use dispatch.

Storing or not the processed data depends on how many times that operation has to be performed afterwards, and if the time required for that is relevant.

---

<div class="post-metadata">

**Author:** ![Iagoba\_Apellaniz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/iagoba_apellaniz/32/34406_2.png) [@Iagoba\_Apellaniz](https://discourse.julialang.org/u/Iagoba_Apellaniz)\
**Post date:** [May 13, 2021, 1:40am UTC](https://discourse.julialang.org/t/doing-trivial-transformations-and-assertions-inside-a-struct-definition/61054/7 "2021-05-13T01:40:51Z")

</div>

Yes! This is true!

FWIW, take care with the types. I think it is better to write code without type annotations until you are sure that everything works.

> [@lmiq](#):
>
> ```julia
> julia> struct Market{T,S}
> qualities::Vector{T}  
> prices::Vector{S}
> normalized_prices::Vector{S}
> end
> 
> ```

For instance, if one calls `Market([1, 2], [2, 3])` in your example it would rise an error because prices’ elements are integers while normalized\_prices’ are floating point numbers.

---

<div class="post-metadata">

**Author:** ![maxkapur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maxkapur/32/21208_2.png) [@maxkapur](https://discourse.julialang.org/u/maxkapur)\
**Post date:** [May 13, 2021, 1:43am UTC](https://discourse.julialang.org/t/doing-trivial-transformations-and-assertions-inside-a-struct-definition/61054/8 "2021-05-13T01:43:32Z")

</div>

@Iagoba_Apellaniz Unless I am mistaken, I believe that this `getproperty` method will compute the sum and divide every time it is called, right? Or maybe the compiler will optimize that away?

I find @OlivierHnt’s solution to be the most “educational” in that it shows me the proper syntax for constructors. But in practice, @lmiq’s approach in the second code block seems most natural for what I am trying to do.

---

<div class="post-metadata">

**Author:** ![Iagoba\_Apellaniz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/iagoba_apellaniz/32/34406_2.png) [@Iagoba\_Apellaniz](https://discourse.julialang.org/u/Iagoba_Apellaniz)\
**Post date:** [May 13, 2021, 1:49am UTC](https://discourse.julialang.org/t/doing-trivial-transformations-and-assertions-inside-a-struct-definition/61054/9 "2021-05-13T01:49:12Z")

</div>

Yes, it performs the sum and it divides every time you call it. Now it depends on you. Take care with the type annotations.

DELETED: Maybe you can leave without type annotation the normalized\_prices field

---

<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:** [May 13, 2021, 1:53am UTC](https://discourse.julialang.org/t/doing-trivial-transformations-and-assertions-inside-a-struct-definition/61054/10 "2021-05-13T01:53:28Z")

</div>

> [@Iagoba\_Apellaniz](#):
>
> Maybe you can leave without type annotation the normalized\_prices field.

Uhm… Probably not. That would make it type unstable. The simplest is to just declare explicitly that it is a `Vector{Float64}`. But probably prices are always that as well and the constructor with the same element for both is fine.
