# Check type stability of a struct

**URL:** https://discourse.julialang.org/t/check-type-stability-of-a-struct/85343
**Category:** Performance
**Tags:** struct, type-stability
**Created:** [August 5, 2022, 1:00pm UTC](https://discourse.julialang.org/t/check-type-stability-of-a-struct/85343 "2022-08-05T13:00:55Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![filchristou](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/filchristou/32/26760_2.png) [@filchristou](https://discourse.julialang.org/u/filchristou)
#### Post date: [August 5, 2022, 1:00pm UTC](https://discourse.julialang.org/t/check-type-stability-of-a-struct/85343/1 "2022-08-05T13:00:55Z")

</div>

We usually speak of type stability for functions and we also have the tools to determine that (like `@code_warntype`).  
But say I would like to check whether a struct is type-stable, in the sense that ~~it is well defined and~~ no field is of an abstract type.  
For the small structs it is trivial, but **for long composite nested structs it is quite hard to inspect it manually**.  
Is there a tool to handle this automatically ?

_example:_

```julia
struct Alpha{T,R}
  x::T
  y::R
end

a1 = Alpha{Real, Int}(1,2)
a2 = Alpha{Int,Int}(1,2)

# desired hypothetical function
istypestable(a1) #returns false
istypestable(a2) #returns true

```

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [August 5, 2022, 2:17pm UTC](https://discourse.julialang.org/t/check-type-stability-of-a-struct/85343/2 "2022-08-05T14:17:08Z")

</div>

> [@filchristou](#):
>
> But say I would like to check whether a struct is type-stable, in the sense that it is well defined and no field is of an abstract type.

Not sure what exactly mean with fields being “well defined” (they always are), but this should do what you’re looking for:

```julia
julia> allconcrete(x::T) where T = all(isconcretetype, fieldtypes(T))
allconcrete (generic function with 1 method)

julia> allconcrete(a1)
false

julia> allconcrete(a2)
true

```

Note that this works through reflection via `fieldtypes`.

“type stable” as a term only makes sense in the context of a function using an object, since type stability only refers to some function whose return type depends on the _value_ of its arguments instead of its types. It’s true that abstractly typed fields can lead to type instabilities in functions using that type, but I’m not sure we should refer to structs with non-concretely typed fields as “type unstable”. There are valid reasons for having a field typed as e.g. `Any` - for example when the field can take on a diverse number of types and specializing on it would not help (or even hinder) performance.

---

<div class="post-metadata">

### Author: ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)
#### Post date: [August 5, 2022, 2:55pm UTC](https://discourse.julialang.org/t/check-type-stability-of-a-struct/85343/3 "2022-08-05T14:55:22Z")

</div>

It better be recursive, like `allconcrete(::Type{T}) where T = isconcretetype(T) && all(allconcrete, fieldtypes(T))`.

---

<div class="post-metadata">

### Author: ![filchristou](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/filchristou/32/26760_2.png) [@filchristou](https://discourse.julialang.org/u/filchristou)
#### Post date: [August 5, 2022, 3:16pm UTC](https://discourse.julialang.org/t/check-type-stability-of-a-struct/85343/4 "2022-08-05T15:16:56Z")

</div>

yes, there are cases like

```julia
cc = Alpha{Int, Alpha{Int, Real}}(1, Alpha{Int,Real}(2,3))

```

where only the recursive function will give the correct result.

However both fail to detect

```julia
julia> abv = Alpha{Vector{Real}, Int}(Vector{Real}([1,2,3]), 3)
Alpha{Vector{Real}, Int64}(Real[1, 2, 3], 3

```

because `Vector{Real} |> fieldtypes` is empty.

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [August 5, 2022, 5:24pm UTC](https://discourse.julialang.org/t/check-type-stability-of-a-struct/85343/5 "2022-08-05T17:24:33Z")

</div>

> [@filchristou](#):
>
> However both fail to detect
> 
> ```julia
> julia> abv = Alpha{Vector{Real}, Int}(Vector{Real}([1,2,3]), 3)
> Alpha{Vector{Real}, Int64}(Real[1, 2, 3], 3
> 
> ```
> 
> because `Vector{Real} |> fieldtypes` is empty.

You’re not going to get around specializing the code in general, since type parameters are not necessarily linked to the field types.

---

<div class="post-metadata">

### Author: ![filchristou](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/filchristou/32/26760_2.png) [@filchristou](https://discourse.julialang.org/u/filchristou)
#### Post date: [August 8, 2022, 2:28pm UTC](https://discourse.julialang.org/t/check-type-stability-of-a-struct/85343/6 "2022-08-08T14:28:45Z")

</div>

I understand that there can be the case that a parameter type might not be linked to a specific field, and thus there will be no negative impact in performance for abstract types.  
e.g.:

```julia
struct Beta{T} end;
b = Beta{Number}()

#desired behavior
istypestable(b) # returns true

```

In these cases, the parameter is mostly used for specialization.

Maybe it’s useful to translate the problem in the function domain.  
E.g. I could write something like this, in order to recursively evaluate all fields from the struct:

```julia
@inline function teststab(a::R) where R
    if isprimitivetype(R)
        return a
    else
        for x in getfield.([a], fieldnames(R))
            testalpha(x)
        end
    end
end

```

upon which I can call `code_warntype`

 ![image](https://global.discourse-cdn.com/julialang/original/3X/4/3/43521543267ca10941956772e5d86e98b41d824a.png)

Unfortunately this version doesn’t really work.  
E.g. the following should be red-free since it’s type stable

 ![image](https://global.discourse-cdn.com/julialang/original/3X/6/e/6ea12c111eee745f0217219d2a0162073251e3d7.png)

The problem is that the compiler inside the `for` loop doesn’t specialize on the type of each field `x` although it should be statically retrievable.  
Any ideas how to proceed ?
