# Implementing own \`size()\` function for a \`struct\` and its performance

**URL:** https://discourse.julialang.org/t/implementing-own-size-function-for-a-struct-and-its-performance/19008
**Category:** Performance
**Tags:** question, array
**Created:** [December 26, 2018, 7:41pm UTC](https://discourse.julialang.org/t/implementing-own-size-function-for-a-struct-and-its-performance/19008 "2018-12-26T19:41:37Z")
**Posts on this page:** 15
**Page:** 1

<div class="post-metadata">

### Author: ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)
#### Post date: [December 26, 2018, 7:41pm UTC](https://discourse.julialang.org/t/implementing-own-size-function-for-a-struct-and-its-performance/19008/1 "2018-12-26T19:41:37Z")

</div>

I am trying to have a `struct` for one of my types, that (among others for the nonMWE) keeps an array as a value. I would like to have a `size` function that works on the encapsulated array. The MWE is as follows

```julia
import Base: size
struct MyType
    value::Array{Float64,N} where N
    name::String
end
getValue(a::MyType) = a.value
size(a::MyType,k...) = size(getValue(a),k...)

function f(a::MyType,b::MyType)::MyType
  if size(a)==size(b)
    c = MyType( a.value .+ b.value, string(a.name,"-",b.name) )
  end
  return c
end

a = MyType(ones(3,3), "A")
b = MyType(zeros(3,3), "B")

f(a,b)
@code_warntype f(a,b)

```

So the function `f` creates a new `MyType` based on two types and needs size as a check. However, the return type of `size` that I implemented. The complete `code_warntype` is

```julia
Body::MyType
10 1 ─ %1 = invoke Main.size(_2::MyType)::Any │
   │ %2 = invoke Main.size(_3::MyType)::Any │
   │ %3 = (%1 == %2)::Any │
   └── goto #3 if not %3 │
11 2 ─ %5 = Base.Broadcast.materialize::Core.Compiler.Const(Base.Broadcast.materialize, false) │
   │ %6 = (Base.getfield)(a, :value)::Array{Float64,N} where N │╻ getproperty
   │ %7 = (Base.getfield)(b, :value)::Array{Float64,N} where N ││
   │ %8 = Main.:+::Core.Compiler.Const(+, false) │
   │ %9 = (Base.Broadcast.combine_styles)(%6, %7)::Any │╻ broadcasted
   │ %10 = (Base.Broadcast.broadcasted)(%9, %8, %6, %7)::Any ││
   │ %11 = (%5)(%10)::Any │
   │ %12 = (Base.getfield)(a, :name)::String │╻ getproperty
   │ %13 = (Base.getfield)(b, :name)::String ││
   │ %14 = invoke Main.string(%12::String, "-"::String, %13::Vararg{String,N} where N)::String │
   └── %15 = (Main.MyType)(%11, %14)::MyType │
13 3 ─ %16 = φ (#2 => true, #1 => false)::Bool │
   │ %17 = φ (#2 => %15, #1 => #undef)::Core.Compiler.MaybeUndef(MyType) │
   │ $(Expr(:throw_undef_if_not, :c, :(%16))) │
   └── return %17

```

(and I am still trying to understand all of this output) - but directly the first two ones (and from that the third) worries me a little – how can i get my own `size` function to have the same return type as the original `size`?

and a short side question – is it (performance wise) the best way to create an own `MyType` for the result `c`?

Any further ideas to optimize a code like this are of course also welcome.

---

<div class="post-metadata">

### Author: ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)
#### Post date: [December 26, 2018, 8:04pm UTC](https://discourse.julialang.org/t/implementing-own-size-function-for-a-struct-and-its-performance/19008/2 "2018-12-26T20:04:02Z")

</div>

Some ideas:

1. Change `Array{Float64,N} where N` to a type parameter as such:

```julia
struct MyType{Tvalue <: Array{Float64}}
    value::Tvalue
    name::String
end

```

1. There is no need for `::MyType` for the function output. Julia should infer this automatically.
2. If the condition `size(a)==size(b)` is false, `c` will be undefined. You need to define a default `c`, or explicitly throw and error if the condition is false.

---

<div class="post-metadata">

### Author: ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)
#### Post date: [December 26, 2018, 8:18pm UTC](https://discourse.julialang.org/t/implementing-own-size-function-for-a-struct-and-its-performance/19008/3 "2018-12-26T20:18:05Z")

</div>

Neat, that already fixes all my code warnings this issue was about. I still have to learn when typed structs are the preferred way to go.

Concerning 2. – yes I hoped so and yes Julia does, just within trying to find something myself I tried adding that  
Concerning 3. – yes of course, I meant to throw an error (actaually the nonMWE code does), just missed that point when shortly making up my MWE 🙂

Thanks!

---

<div class="post-metadata">

### Author: ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)
#### Post date: [December 26, 2018, 8:55pm UTC](https://discourse.julialang.org/t/implementing-own-size-function-for-a-struct-and-its-performance/19008/4 "2018-12-26T20:55:51Z")

</div>

> [@kellertuer](#):
>
> I still have to learn when typed structs are the preferred way to go.

If you want to dispatch on the struct types to do something special for each type. Performance-wise, it shouldn’t make a difference, builtin Julia types are more than enough for simple programming tasks. Structs can also closely map conceptual abstractions, e.g. `Cube`, `Point`, `Person`, etc. if you are trying to build a complete framework of some sort.

---

<div class="post-metadata">

### Author: ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)
#### Post date: [December 26, 2018, 9:02pm UTC](https://discourse.julialang.org/t/implementing-own-size-function-for-a-struct-and-its-performance/19008/5 "2018-12-26T21:02:59Z")

</div>

It should matter for performance in this case as the original field type wasn’t concrete. Julia can’t know the dimensionality of the contained array from the type alone. This is different for the parametric type as the type parameter specifies the concrete array type, including the dimensionality.

---

<div class="post-metadata">

### Author: ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)
#### Post date: [December 26, 2018, 9:07pm UTC](https://discourse.julialang.org/t/implementing-own-size-function-for-a-struct-and-its-performance/19008/6 "2018-12-26T21:07:41Z")

</div>

FWIW, I was commenting on when to use structs for the output of functions as opposed to simple tuples for example. That’s how I understood the question anyways.

---

<div class="post-metadata">

### Author: ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)
#### Post date: [December 26, 2018, 9:10pm UTC](https://discourse.julialang.org/t/implementing-own-size-function-for-a-struct-and-its-performance/19008/7 "2018-12-26T21:10:17Z")

</div>

I see, makes sense. I obviously took the question as “when should I use type parameters”.

---

<div class="post-metadata">

### Author: ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)
#### Post date: [December 26, 2018, 9:12pm UTC](https://discourse.julialang.org/t/implementing-own-size-function-for-a-struct-and-its-performance/19008/8 "2018-12-26T21:12:32Z")

</div>

Thanks for the implementation, I will adopt that for my type(s).

---

<div class="post-metadata">

### Author: ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)
#### Post date: [December 26, 2018, 9:15pm UTC](https://discourse.julialang.org/t/implementing-own-size-function-for-a-struct-and-its-performance/19008/9 "2018-12-26T21:15:17Z")

</div>

My question was mainly when to use typed types (typed structs) instead of just types (structs) – but the idea that Julia can not see the dimensionality of internal variables just from the type helpes a lot. I am indeed working on a certain framework (hopefully the first parts might be finished after getting through all code warnings); and I am indeed mapping conceptual abstractions using structs.  
Thanks for the explanation.

---

<div class="post-metadata">

### Author: ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)
#### Post date: [December 26, 2018, 9:18pm UTC](https://discourse.julialang.org/t/implementing-own-size-function-for-a-struct-and-its-performance/19008/10 "2018-12-26T21:18:42Z")

</div>

FWIW, “typed structs” typically go by the name “parametric types/structs”. See for example the corresponding section on the Julia docs.

---

<div class="post-metadata">

### Author: ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)
#### Post date: [January 2, 2019, 2:50pm UTC](https://discourse.julialang.org/t/implementing-own-size-function-for-a-struct-and-its-performance/19008/12 "2019-01-02T14:50:01Z")

</div>

While transferring that to my larger project, the error (from `@code_warntype`) still stays; it’s related to `getfield` but I actally can’t narrow that further down.

Some lines are just like

```julia
  6 ┄─ %37 = (Core.getfield)(%1, :contents)::Any

```

where none of my own types even have a `contents` field. Any idea where that comes from? For me it’s really hard to read the `code_warntype` output. Since `Traceur.jl` seems to fail (with not finding some function) - is there other tools to help with avoiding too loosely typed lines?

I am a little lost with these optimizations, since I can’t narrow down the code lines where they appear.

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [January 2, 2019, 3:20pm UTC](https://discourse.julialang.org/t/implementing-own-size-function-for-a-struct-and-its-performance/19008/13 "2019-01-02T15:20:03Z")

</div>

A self-contained MWE of the most recent iteration would be very helpful.

---

<div class="post-metadata">

### Author: ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)
#### Post date: [January 3, 2019, 8:21am UTC](https://discourse.julialang.org/t/implementing-own-size-function-for-a-struct-and-its-performance/19008/14 "2019-01-03T08:21:45Z")

</div>

Yes, I am aware of that and I am currently not able to extract that. Maybe even getting to the MWE would resolve my problem. So in short: All my MWEs I extract work, the large project I am working on does not and gives me `Any` `code_warntype`s. Sorry. As soon as I get to an MWE that reproduces my problem, I’ll come back.

I thought that maybe the generic result posted could already indicate something.

_Edit_: Compared to the introductionary example, my project code _should_ do the same, but it introduces for the Variable `a` (and also `b`) a `Core.Box`. The type is a little more complicated as shown in the following (where I also try to get my example encapsulated into a `runExample`.

```julia
import Base: size,+
abstract type MyAbstractType end
getValue(x::T) where T <: MyAbstractType = x.value
struct MySimpleType <: MyAbstractType
  value::Float64
end
+(a::T,b::T) where {T <: MyAbstractType} = T(getValue(a)+getValue(b))
struct MyType{TA <: AbstractArray{T,N} where {T <: MyAbstractType, N}} <: MyAbstractType
    value::TA
    name::String
end
size(x::MyType, k...) = size(getValue(x),k...)
function +(a::MyType,b::MyType)::MyType
  if size(a)==size(b)
    d = length(size(a))
    c = MyType( getValue(a) + getValue(b), string(a.name,"-($(d))-",b.name) )
  else
    throw( ErrorException("Both Variables have to be of same length") )
  end
  return c
end

function runExample()
  a1 = MySimpleType.(ones(3,3))
  a2 = MySimpleType.(ones(3,3))
  a = MyType( [a1; a2] , "A")
  b = MyType( MySimpleType.(zeros(6,3)), "B")
  return a+b
end
runExample()
code_warntype(runExample, (); verbose_linetable=true )

```

However, also for this example the problem of a `Core.Box` does not occur and I can’t get my MWE any closer to the original code, The first `Any`I then get is when computing `d` within `+` which is the first point at which the original code tries to access the contents of `a`.

Again: This MWE does _not_ reproduce the problem, but I can not find any difference between this MWE and my original code, that is not so easy to extract from the package, but also involves this recursive type this example has (and yes sorry I am just running out of ideas what to test).

---

<div class="post-metadata">

### Author: ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)
#### Post date: [January 3, 2019, 4:30pm UTC](https://discourse.julialang.org/t/implementing-own-size-function-for-a-struct-and-its-performance/19008/15 "2019-01-03T16:30:58Z")

</div>

My final remarks, since I am really running out of ideas is – the only difference from the last code to my complete code is, that the `MySimpleType` is not a value but a vector ( `Vector{Float64}`), that does not change the results in the above example, it still has stable types.

However, also only in my larger example (though not in the MWE), adding a constructor to (hence within) `MyType` like

```julia
    MyType{TA,TB}(v,d) where {TA <: AbstractArray{T,N} where {T <: MyAbstractType, N}, TB <: Tuple{Vararg{Int}} }= new(v,d)

```

yields that `code_warntype` does not produce any `Core.Box`es anymore any no `Any`s, however the code itself of course does not work anymore, since the constructor now requires the types to be specified on every call (which is tedious to write). On the other hand adding the easier (outer) constructor (so outside of `MyType`) like

```julia
MyType(v::TA,d::TB) where {TA <: AbstractArray{T,N} where {T <: MyAbstractType, N}, TB <: Tuple{Vararg{Int}} }= MyType{TA,TB}(v,d)

```

solves this problem and the constructors as in the MWE work again. In the MWE this also compiles fine. However in my larger code (with vector instead of float, though that also does not break the MWE)

- introducing the inner constructor solves all code warnings but the code does not run
- introducing the outer constructor additionally makes the code run but reintroduces the code warnings.

The definition of `a` seems to be the culprit, it just appears for the size (variable `d`) for the first time and `axis stored in a `Core.Box` - again only in my larger example though the example above is the same with different names copied together into one example. The output is even stranger. Adapted (as said the MWE does not reproduce, and I really don’t know why anymore)

```julia
    %23 = %new(MyType{Array{MySimpleType,1}}, %22)::MyType{Array{MySimpleType,1}}
    │ (Core.setfield!)(%1, :contents, %23)
│ (Core.setfield!)(%2, :contents, 10.0)

```

So it seems to defer the type correctly in its compiled command 23 but then decides to still put it in a `Core.Box`. Even stranger, the following box that’s filled is for a line that just reads ` α = 10.`(that’s why I added that, too). I don’t understand any of those lines. Of course this causes many other problems when reusing that line. (`%22`) is the result of the `vcat` from within the `runExample` and returns the proper array of SimpleTypes.

---

<div class="post-metadata">

### Author: ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)
#### Post date: [January 4, 2019, 8:45am UTC](https://discourse.julialang.org/t/implementing-own-size-function-for-a-struct-and-its-performance/19008/16 "2019-01-04T08:45:20Z")

</div>

Okay, I found the culprit: Besides.`size had another function that was not typestyle and somehow that induced so many boxes and errors that it was hard to find that. I am left with another problem, but that is merely for another thread, because it’s not related to the problem discussed here. Thanks for all your help.
