# Flattening Tuples of Types that form the parameter of a supertype

**URL:** <https://discourse.julialang.org/t/flattening-tuples-of-types-that-form-the-parameter-of-a-supertype/79528>\
**Category:** General Usage\
**Created:** [April 15, 2022, 12:07pm UTC](https://discourse.julialang.org/t/flattening-tuples-of-types-that-form-the-parameter-of-a-supertype/79528 "2022-04-15T12:07:14Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Dhruva2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dhruva2/32/18475_2.png) [@Dhruva2](https://discourse.julialang.org/u/Dhruva2)\
**Post date:** [April 15, 2022, 12:07pm UTC](https://discourse.julialang.org/t/flattening-tuples-of-types-that-form-the-parameter-of-a-supertype/79528/1 "2022-04-15T12:07:14Z")

</div>

Dear all,

Below is an MWE of the code I’m writing.

I’m using the abstract supertype Pairer as a ‘tag’. Its two type parameters specify the ionic inputs and outputs to concrete subtypes.

Joiner and Extender make new concrete subtypes of Pairer out of old ones, in such a way that the ionic inputs are extended:

```julia
abstract type Ion end
struct Sodium <: Ion end
struct Potassium <: Ion end
struct Calcium <: Ion end
struct Proton <: Ion end

abstract type Pairer{Inputs,Outputs} end
## Inputs and Outputs are either Ions or tuples of Ions 

somehow_merge(Inputs, NewInputs) = Tuple{Inputs,NewInputs}

abstract type Extender{ExtraInput} end
## ExtraInput is either Ion or tuple of Ions 

struct Joiner{Input,ExtraInput,Output} <: Pairer{somehow_merge(Input, ExtraInput),Output}
    s::Pairer{Input,Output}
    e::Extender{ExtraInput}
end

struct HappyPairer <: Pairer{Sodium,Potassium} end
struct SadPairer <: Pairer{Tuple{Sodium,Proton,Calcium},Calcium} end
struct CalcExtender <: Extender{Calcium} end

show_inputs(p::Pairer{S,A}) where {S,A} = S

hap = HappyPairer()
sad = SadPairer()
c = CalcExtender()
j = Joiner(hap, c)
show_inputs(j)
j2 = Joiner(sad, c)
show_inputs(j2)

```

`show_inputs(j)` gives: `Tuple{Sodium, Calcium}`. Great.

`show_inputs(j2)` gives `Tuple{Tuple{Sodium, Proton, Calcium}, Calcium}`. **Bad**.

What I want is for it to be `Tuple{Sodium, Proton, Calcium}`. In other words, flatten the nested tuple and take out unique elements.

But I haven’t been able to figure out a `somehow_merge` that can do this for tuples.

Now I should be able to pick through `t1.parameters` and `t2.parameters` where t1 and t2 are tuples of types, and then concatenate them to make a new tuple with all the elements of t1 and t2.

However, if I try modifying `somehow_merge` to do this, I get errors like

```julia
exception =
│ type TypeVar has no field parameters.

```

…except it clearly does!

What’s going wrong? Can anybody make a `somehow_merge` that gives

```julia
show_inputs(j2) 
Tuple{Sodium, Proton, Calcium}

```

Thank you so much!

---

<div class="post-metadata">

**Author:** ![goerch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerch/32/29122_2.png) [@goerch](https://discourse.julialang.org/u/goerch)\
**Post date:** [April 15, 2022, 3:36pm UTC](https://discourse.julialang.org/t/flattening-tuples-of-types-that-form-the-parameter-of-a-supertype/79528/2 "2022-04-15T15:36:30Z")

</div>

I’ve got an approximation that should work for nested tuples up to a certain size

```julia
typeflatten(::Type{T}) where {T} = (T,)
typeflatten(::Type{Tuple{T1}}) where {T1} = (typeflatten(T1)...,)
typeflatten(::Type{Tuple{T1, T2}}) where {T1, T2} = (typeflatten(T1)..., typeflatten(T2)...)
typeflatten(::Type{Tuple{T1, T2, T3}}) where {T1, T2, T3} = (typeflatten(T1)..., typeflatten(T2)..., typeflatten(T3)...)

@show Tuple{typeflatten(Tuple{Tuple{Int}, Int})...}
@show Tuple{typeflatten(Tuple{Tuple{Int, Int}, Int})...}
@show Tuple{typeflatten(Tuple{Int, Tuple{Int, Int}})...}
@show Tuple{typeflatten(Tuple{Tuple{Tuple{Int, Int, Int}}, Tuple{Tuple{Int, Int, Int}}, Tuple{Tuple{Int, Int, Int}}})...}

```

yielding

```julia
Tuple{typeflatten(Tuple{Tuple{Int}, Int})...} = Tuple{Int64, Int64}
Tuple{typeflatten(Tuple{Tuple{Int, Int}, Int})...} = Tuple{Int64, Int64, Int64}
Tuple{typeflatten(Tuple{Int, Tuple{Int, Int}})...} = Tuple{Int64, Int64, Int64}
Tuple{typeflatten(Tuple{Tuple{Tuple{Int, Int, Int}}, Tuple{Tuple{Int, Int, Int}}, Tuple{Tuple{Int, Int, Int}}})...} = NTuple{9, Int64}

```

Would be interesting to know if there is a better solution.

Edit: to apply this to your problem you would use

```julia
show_inputs(p::Pairer{S,A}) where {S,A} = Tuple{typeflatten(S)...}

```

---

<div class="post-metadata">

**Author:** ![Dhruva2](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dhruva2/32/18475_2.png) [@Dhruva2](https://discourse.julialang.org/u/Dhruva2)\
**Post date:** [April 15, 2022, 6:06pm UTC](https://discourse.julialang.org/t/flattening-tuples-of-types-that-form-the-parameter-of-a-supertype/79528/3 "2022-04-15T18:06:13Z")

</div>

thanks, that’s a nice approximate solution!

for my use case, i decided to allow nested tuples, and access their elements through a recursive algorithm like so:

```julia
function testsensed(s::DataType) # takes in potentially nested tuple
    map(fieldtypes(s)) do el
        el <: Tuple && return testsensed(el)
        return (el,)
    end |> Iterators.flatten |> collect |> unique!
end

```

But i’d also be interested, from a learning julia point of view, to see any alternatives that directly solve the issue
