# \[ANN\] ConcreteStructs.jl - Cut the boilerplate when concretely parameterizing structs

**URL:** <https://discourse.julialang.org/t/ann-concretestructs-jl-cut-the-boilerplate-when-concretely-parameterizing-structs/47274>\
**Category:** Package Announcements\
**Created:** [September 25, 2020, 4:09pm UTC](https://discourse.julialang.org/t/ann-concretestructs-jl-cut-the-boilerplate-when-concretely-parameterizing-structs/47274 "2020-09-25T16:09:16Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![jonniedie](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jonniedie/32/12842_2.png) [@jonniedie](https://discourse.julialang.org/u/jonniedie)\
**Post date:** [September 25, 2020, 4:09pm UTC](https://discourse.julialang.org/t/ann-concretestructs-jl-cut-the-boilerplate-when-concretely-parameterizing-structs/47274/1 "2020-09-25T16:09:16Z")

</div>

## The Problem

Defining concretely parameterized structs involves quite a bit of boilerplate code. Consider the following definition from DifferentialEquations.jl:

```julia
struct ODEFunction{iip,F,TMM,Ta,Tt,TJ,JVP,VJP,JP,SP,TW,TWt,TPJ,S,TCV} <: AbstractODEFunction{iip}
  f::F
  mass_matrix::TMM
  analytic::Ta
  tgrad::Tt
  jac::TJ
  jvp::JVP
  vjp::VJP
  jac_prototype::JP
  sparsity::SP
  Wfact::TW
  Wfact_t::TWt
  paramjac::TPJ
  syms::S
  colorvec::TCV
end

```

The only type parameter that you explicitly care about here is the first one, `iip`. The rest are just there to make sure `ODEFunction` is concretely typed. It’s a little annoying that you have to come up with type parameter names for types you don’t really care about, right? And what’s more, parameterizing structs too early on makes it a bit of a pain to change your code later (did I remember to put a new type parameter in when I added a field to my struct definition?). Wouldn’t it be cool if there was a macro to just do this for you automatically?

## A Solution

[ConcreteStructs.jl](https://github.com/jonniedie/ConcreteStructs.jl) exports the macro `@concrete` that will add type parameters to your struct for any field where type parameters aren’t given. So in that `ODEFunction` example, we could get the same result just by saying:

```julia
@concrete struct ODEFunction{iip} <: AbstractODEFunction{iip}
  f
  mass_matrix
  analytic
  tgrad
  jac
  jvp
  vjp
  jac_prototype
  sparsity
  Wfact
  Wfact_t
  paramjac
  syms
  colorvec
end

```

This also works with more complicated parameter dependencies like:

```julia
@concrete struct MyType{T,N,A<:AbstractArray{T,N}} <: AbstractArray{T,N}
    a::A
    b::T
    c
    function MyType(a::AbstractArray{T,N}, b::B, c) where {T,N,B}
        Tnew = promote_type(T, B)
        a, b = Tnew.(a), Tnew(b)
        return new{Tnew,N,typeof(a),typeof(c)}(a, b, c)
    end
end

```

Additionally the `@concrete` macro supports a keyword `terse` that will cause the struct type to print compactly in the `:compact => true` mode of an `IOContext`. The current implementation looks like this (but there is an [issue](https://github.com/jonniedie/ConcreteStructs.jl/issues/1) open to decide on alternative implementations because I’m not totally convinced this is the best way to go):

```julia
@concrete terse mutable struct AnotherType{C}
    a::Symbol
    b
    c::C
end

```

```julia-repl
julia> x = AnotherType(:eyyy, 1f0, (1,2.0))
AnotherType(:eyyy, 1.0f0, (1, 2.0))

julia> typeof(x)
AnotherType{Tuple{Int64,Float64},Float32}

```

Note that the given type parameters always come first in the type signature (the type of `c` here comes before the type of `b` because `c`’s type was explicitly given.

Anyway. Let me know what you think or if you have any suggestions for improvement here.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [September 25, 2020, 5:27pm UTC](https://discourse.julialang.org/t/ann-concretestructs-jl-cut-the-boilerplate-when-concretely-parameterizing-structs/47274/2 "2020-09-25T17:27:11Z")

</div>

You are a good human.

---

<div class="post-metadata">

**Author:** ![oschulz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oschulz/32/2998_2.png) [@oschulz](https://discourse.julialang.org/u/oschulz)\
**Post date:** [September 26, 2020, 7:44am UTC](https://discourse.julialang.org/t/ann-concretestructs-jl-cut-the-boilerplate-when-concretely-parameterizing-structs/47274/3 "2020-09-26T07:44:53Z")

</div>

Oh, this is very nice! Would it be possible to support type restrictions? E.g.

```julia
@concrete struct MyStruct
    a
    b<:Number
    c<:AbstractVector
end

```

as an equivalent for

```julia
struct MyStruct{A,B<:Number,C<:AbstractVector}
    a::A
    b::B
    c::C
end

```

Or may even (I know, now I’m getting greedy)

```julia
@concrete struct MyStruct
    a
    b<:Number
    c<:AbstractVector{typeof(b)}
end

```

as an equivalent for

```julia
struct MyStruct{A,B<:Number,C<:AbstractVector{B}}
    a::A
    b::B
    c::C
end

```

---

<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:** [September 26, 2020, 7:51am UTC](https://discourse.julialang.org/t/ann-concretestructs-jl-cut-the-boilerplate-when-concretely-parameterizing-structs/47274/4 "2020-09-26T07:51:33Z")

</div>

> [@oschulz](#):
>
> Would it be possible to support type restrictions?

If not, I have a very similar macro that supports this implemented in one of my packages. [Here](https://gist.github.com/mohamed82008/6348cee55cee42e3674822e02639a881) is the entire implementation and docstring. It doesn’t support inner constructors though which ConcreteStructs does. So it may be nice to combine the 2 implementations.

Edit: would also be nice to make it play nicely with `@with_kw` of Parameters.jl.

---

<div class="post-metadata">

**Author:** ![jcook](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jcook/32/18211_2.png) [@jcook](https://discourse.julialang.org/u/jcook)\
**Post date:** [September 26, 2020, 8:44am UTC](https://discourse.julialang.org/t/ann-concretestructs-jl-cut-the-boilerplate-when-concretely-parameterizing-structs/47274/5 "2020-09-26T08:44:44Z")

</div>

Mind reader! This was what I was scratching my head about only yesterday.

---

<div class="post-metadata">

**Author:** ![TsurHerman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tsurherman/32/1234_2.png) [@TsurHerman](https://discourse.julialang.org/u/TsurHerman)\
**Post date:** [September 26, 2020, 11:14am UTC](https://discourse.julialang.org/t/ann-concretestructs-jl-cut-the-boilerplate-when-concretely-parameterizing-structs/47274/6 "2020-09-26T11:14:42Z")

</div>

I wonder why isn’t it the default behaviour, what is the reason dispatch only looks in the outer type parameters?

---

<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:** [September 26, 2020, 11:20am UTC](https://discourse.julialang.org/t/ann-concretestructs-jl-cut-the-boilerplate-when-concretely-parameterizing-structs/47274/7 "2020-09-26T11:20:58Z")

</div>

Think of mutable types with fields that start as `nothing` and then get assigned a value. If the type of the field is `Nothing`, you can’t assign it properly.

---

<div class="post-metadata">

**Author:** ![willtebbutt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/willtebbutt/32/6790_2.png) [@willtebbutt](https://discourse.julialang.org/u/willtebbutt)\
**Post date:** [September 26, 2020, 12:22pm UTC](https://discourse.julialang.org/t/ann-concretestructs-jl-cut-the-boilerplate-when-concretely-parameterizing-structs/47274/8 "2020-09-26T12:22:40Z")

</div>

Looks like several of us have the [same feature request](https://github.com/jonniedie/ConcreteStructs.jl/issues/3) 😂

---

<div class="post-metadata">

**Author:** ![jonniedie](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jonniedie/32/12842_2.png) [@jonniedie](https://discourse.julialang.org/u/jonniedie)\
**Post date:** [September 26, 2020, 12:45pm UTC](https://discourse.julialang.org/t/ann-concretestructs-jl-cut-the-boilerplate-when-concretely-parameterizing-structs/47274/9 "2020-09-26T12:45:07Z")

</div>

@oschulz It seems that there is enough desire for this feature that it’s worth considering. I laid out my objections [here](https://github.com/jonniedie/ConcreteStructs.jl/issues/3), but I feel like this would still be doable in some form. On the “for it” side, it is worth considering that both you and @willtebbutt proposed the same syntax independently.

---

<div class="post-metadata">

**Author:** ![jonniedie](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jonniedie/32/12842_2.png) [@jonniedie](https://discourse.julialang.org/u/jonniedie)\
**Post date:** [September 26, 2020, 12:48pm UTC](https://discourse.julialang.org/t/ann-concretestructs-jl-cut-the-boilerplate-when-concretely-parameterizing-structs/47274/10 "2020-09-26T12:48:04Z")

</div>

I’d definitely like this to play more nicely with other struct definition macros, especially `Base.@kwdef` and `@with_kw`.

---

<div class="post-metadata">

**Author:** ![oschulz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oschulz/32/2998_2.png) [@oschulz](https://discourse.julialang.org/u/oschulz)\
**Post date:** [September 26, 2020, 8:52pm UTC](https://discourse.julialang.org/t/ann-concretestructs-jl-cut-the-boilerplate-when-concretely-parameterizing-structs/47274/11 "2020-09-26T20:52:49Z")

</div>

Thanks for considering this!

I’ve often found myself wishing for this that as a language feature, i.e. automatic anonymous type parameters for fields defined as `fieldname<:SomeType`. I assume something like that must have been discussed already, though?

---

<div class="post-metadata">

**Author:** ![Krastanov](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/krastanov/32/6817_2.png) [@Krastanov](https://discourse.julialang.org/u/Krastanov)\
**Post date:** [October 3, 2020, 7:54pm UTC](https://discourse.julialang.org/t/ann-concretestructs-jl-cut-the-boilerplate-when-concretely-parameterizing-structs/47274/12 "2020-10-03T19:54:33Z")

</div>

Could you elaborate for newbies like me why this is important (maybe in the readme)? I would guess it has something to do with otherwise having to encapsulate otherwise untyped objects which causes slow runtime checks. But that does not seem right, as I imagine such runtime checks would be rare enough to not matter?

---

<div class="post-metadata">

**Author:** ![jonniedie](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jonniedie/32/12842_2.png) [@jonniedie](https://discourse.julialang.org/u/jonniedie)\
**Post date:** [October 4, 2020, 12:06am UTC](https://discourse.julialang.org/t/ann-concretestructs-jl-cut-the-boilerplate-when-concretely-parameterizing-structs/47274/13 "2020-10-04T00:06:08Z")

</div>

Yeah definitely. [This page of the docs](https://docs.julialang.org/en/v1/manual/performance-tips/#Avoid-fields-with-abstract-type) describes why you would want to parametrize struct fields. It’s definitely worth linking to this in my README, though. Thanks for the suggestion.

---

<div class="post-metadata">

**Author:** ![Ginter](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ginter/32/9829_2.png) [@Ginter](https://discourse.julialang.org/u/Ginter)\
**Post date:** [October 10, 2020, 4:19am UTC](https://discourse.julialang.org/t/ann-concretestructs-jl-cut-the-boilerplate-when-concretely-parameterizing-structs/47274/14 "2020-10-10T04:19:31Z")

</div>

The other day I started working on the same idea, with the same name too! Thanks a lot for sharing; what a time saver.
