# Stripping parameter from parametric types

**URL:** https://discourse.julialang.org/t/stripping-parameter-from-parametric-types/8293
**Category:** New to Julia
**Tags:** parametric-types
**Created:** [January 11, 2018, 3:03pm UTC](https://discourse.julialang.org/t/stripping-parameter-from-parametric-types/8293 "2018-01-11T15:03:46Z")
**Posts on this page:** 19
**Page:** 1

<div class="post-metadata">

### Author: ![braydenware](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/braydenware/32/2612_2.png) [@braydenware](https://discourse.julialang.org/u/braydenware)
#### Post date: [January 11, 2018, 3:03pm UTC](https://discourse.julialang.org/t/stripping-parameter-from-parametric-types/8293/1 "2018-01-11T15:03:46Z")

</div>

I have writing code that maniuplates containers of arrays of custom types with several parameters, e.g.  
`SomeArrayType{T, G1, G2, N} <: AbstractArray{T, N}`, where the last parameter in SomeArrayType is always the array rank N. The arrays that can be in the container can differ in rank N but otherwise should be the same type, for example `Vector{SomeArray{T, G1, G2}}` which can also be written `Vector{SomeArray{T, G1, G2, N} where N}`.

I’d like to create a function `arraytype` that strips the last (rank) parameter from the type, so that  
`arraytype(::Type{NewArrayType{T, X, Y, Z, N}}) = NewArrayType{T, X, Y, Z}` for any type that might be encountered. How would one write a function that generically strips the last parameter from a type?

---

<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: [January 11, 2018, 4:52pm UTC](https://discourse.julialang.org/t/stripping-parameter-from-parametric-types/8293/2 "2018-01-11T16:52:40Z")

</div>

Not sure if there is an easier way or not, but here is my attempt.

```julia
julia> name(T::DataType) = T.name
name (generic function with 1 method)

julia> name(T::UnionAll) = name(T.body)
name (generic function with 2 methods)

julia> datatype(T::UnionAll) = datatype(T.body)
datatype (generic function with 1 method)

julia> datatype(T::DataType) = T
datatype (generic function with 2 methods)

julia> nvars(T::UnionAll) = 1 + nvars(T.body)
nvars (generic function with 1 method)

julia> nvars(T::DataType) = 0
nvars (generic function with 2 methods)

julia> unionall(T) = eval(Symbol(name(T)))
unionall (generic function with 1 method)

julia> parametersless1(T) = datatype(T).parameters[1:end-nvars(T)-1]
parametersless1 (generic function with 1 method)

julia> @generated function f(::Type{T}) where {T}
           any(isa.(T, (DataType, UnionAll))) || throw("Only supports DataType and UnionAll inputs.")
           n = unionall(T)
           n isa DataType && return :($n)
           ps = parametersless1(T)
           return :($n{$(ps...)})
       end
f (generic function with 1 method)

julia> struct T{S1,S2,S3} end

julia> f(T{1,2,3})
T{1,2,S3} where S3

julia> f(T{1,2})
T{1,S2,S3} where S3 where S2

julia> f(T{1})
T

julia> f(T)
T

julia> f(Int)
Int64

```

You can also make a normal function not a generated one. And you can avoid using `eval` altogether if you find a way to change a `TypeName` to a `UnionAll` in case of parametric types, or to a `DataType` in case of non-parametric types, `eval` was the lazy solution.

---

<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 11, 2018, 5:53pm UTC](https://discourse.julialang.org/t/stripping-parameter-from-parametric-types/8293/3 "2018-01-11T17:53:35Z")

</div>

Here is a prototype for `Array`:

```julia
julia> stripN(::Type{Array{T, N}}) where {T, N} = Array{T, M} where M
stripN (generic function with 1 method)

julia> stripN(Vector{Float64})
Array{Float64,M} where M

```

should be straightforward to do for a type with more parameters.

---

<div class="post-metadata">

### Author: ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)
#### Post date: [January 11, 2018, 6:53pm UTC](https://discourse.julialang.org/t/stripping-parameter-from-parametric-types/8293/4 "2018-01-11T18:53:33Z")

</div>

I think the key point is:

> [@braydenware](#):
>
> for any type that might be encountered.

---

<div class="post-metadata">

### Author: ![braydenware](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/braydenware/32/2612_2.png) [@braydenware](https://discourse.julialang.org/u/braydenware)
#### Post date: [January 11, 2018, 9:30pm UTC](https://discourse.julialang.org/t/stripping-parameter-from-parametric-types/8293/5 "2018-01-11T21:30:25Z")

</div>

Right. That is my current solution - to define a new method or each array type that I need. I was wondering whether I could avoid that by mucking around in the type system.

---

<div class="post-metadata">

### Author: ![jandehaan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jandehaan/32/6805_2.png) [@jandehaan](https://discourse.julialang.org/u/jandehaan)
#### Post date: [January 12, 2018, 4:29pm UTC](https://discourse.julialang.org/t/stripping-parameter-from-parametric-types/8293/6 "2018-01-12T16:29:42Z")

</div>

You may not need a special function. Consider the following approach.

> struct SomeArrayType{T,G1,G2,N} \<: AbstractArray{T,N}  
> content::AbstractArray{T,N}  
> g1::G1  
> g2::G2  
> end

Constructor that automatically defines the value of N by using ndims method:

> SomeArrayType(a::AbstractArray, g1, g2) = SomeArrayType{eltype(a), typeof(g1), typeof(g2), ndims(a)}(a, g1, g2)

The show method requires the size and getindex methods to exist:

> Base.size(a::SomeArrayType) = size(a.content)  
> Base.getindex(a::SomeArrayType, I…) = getindex(a.content, I…)

Now define an instance of SomeArrayType without having to specify N:

> Julia\> SomeArrayType( [1,2,3], ‘a’, 4.0 )  
> 3-element SomeArrayType{Int64,Char,Float64,1}:  
> 1  
> 2  
> 3

---

<div class="post-metadata">

### Author: ![braydenware](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/braydenware/32/2612_2.png) [@braydenware](https://discourse.julialang.org/u/braydenware)
#### Post date: [January 12, 2018, 5:27pm UTC](https://discourse.julialang.org/t/stripping-parameter-from-parametric-types/8293/7 "2018-01-12T17:27:27Z")

</div>

Hey jandehaan, my issue is not dealing with constructors. It’s more of this type of thing:

```julia
arrs = [SomeArrayType( [1,2,3], ‘a’, 4.0 ), SomeArrayType( [1,2,3], ‘a’, 4.0 )]

function func(arrs::Vector{A}) where A<:AbstractArray
    arrs = deepcopy(arrs)
    # some computation involving arrs
    newarr = SomeArrayType( [[1,2,3],[1,2,3],[1,2,3]], ‘a’, 4.0 )
    push!(arrs, newarr) # causes error
    # more computations and collecting arrays into arrs
    return arrs
end

```

The issue is that `arrs` is of type `Vector{SomeArrayType{Int, String, Float, 1}}` and I need to add an array to it of a different rank (i.e. type `SomeArrayType{Int, String, Float, 2}` or for arbitrary ranks.) I can fix it with a call to `convert(Vector{SomeArrayType{Int, String, Float, N} where N}, arrs)` every time I call the function (which is annoying) or inside the function. But inside the function, it’s not clear how to strip the last parameter from the type of `A`.

---

<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: [January 12, 2018, 6:48pm UTC](https://discourse.julialang.org/t/stripping-parameter-from-parametric-types/8293/8 "2018-01-12T18:48:50Z")

</div>

> [@braydenware](#):
>
> I can fix it with a call to convert(Vector{SomeArrayType{Int, String, Float, N} where N}, arrs) every time I call the function (which is annoying) or inside the function.

If you care about performance, this will probably throw it out of the window.

---

<div class="post-metadata">

### Author: ![jandehaan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jandehaan/32/6805_2.png) [@jandehaan](https://discourse.julialang.org/u/jandehaan)
#### Post date: [January 12, 2018, 8:48pm UTC](https://discourse.julialang.org/t/stripping-parameter-from-parametric-types/8293/9 "2018-01-12T20:48:37Z")

</div>

Try this:

```julia
struct SomeArrayType{T,G1,G2,N} <: AbstractArray{T,N} 
    content::AbstractArray{T,N}
    g1::G1
    g2::G2
end

# constructor that automatically defines the value of N
SomeArrayType(a::AbstractArray, g1, g2) = 
    SomeArrayType{eltype(a), typeof(g1), typeof(g2), ndims(a)}(a, g1, g2)

Base.size(a::SomeArrayType) = size(a.content)
Base.getindex(a::SomeArrayType, I...) = size(a.content, I...)

Base.show(io::IO, a::SomeArrayType) = 
    print(io, typeof(a), "(", a.content, ", ", a.g1, ", ", a.g2, ")")

function func(arrs::Vector{A}) where A<:AbstractArray
    arrs = convert(Vector{Base.AbstractArray}, arrs)
    arrs = deepcopy(arrs)
    # some computation involving arrs
    newarr = SomeArrayType( [[1,2,3],[1,2,3],[1,2,3]], 'a', 4.0 )
    push!(arrs, newarr) # causes error
    # more computations and collecting arrays into arrs
    return arrs
end

# now define an instance of SomeArrayType
SomeArrayType([1,2,3], 'a', 4.0)

arrs = [SomeArrayType( [1,2,3], 'a', 4.0 ),  
                      SomeArrayType( [1,2,3], "string", 4.0 )]

func(arrs)

```

The last statement produces:

```julia
3-element Array{AbstractArray,1}:
   SomeArrayType{Int64,Char,Float64,1}([1, 2, 3], a, 4.0)
   SomeArrayType{Int64,String,Float64,1}([1, 2, 3], string, 4.0) 
   SomeArrayType{Array{Int64,1},Char,Float64,1}(
           Array{Int64,1}[[1, 2, 3], [1, 2, 3], [1, 2, 3]], a, 4.0)

```

---

<div class="post-metadata">

### Author: ![jameson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jameson/32/23_2.png) [@jameson](https://discourse.julialang.org/u/jameson)
#### Post date: [January 19, 2018, 8:18pm UTC](https://discourse.julialang.org/t/stripping-parameter-from-parametric-types/8293/10 "2018-01-19T20:18:51Z")

</div>

> [@braydenware](#):
>
> Right. That is my current solution - to define a new method or each array type that I need. I was wondering whether I could avoid that by mucking around in the type system.

No, you can’t. The approved solution is wrong – there’s no relation between the ordering of type parameters of a subtype (in this case, SomeArrayType) and its supertype (AbstractArray). `Tamas_Papp`’s solution is correct. In generic code, this is usually done by calling the `similar` function.

However, we can also generalize that solution to abstract types as follows (by adding in `<:` so that it can select subtypes):

```julia
stripN(::Type{<:AbstractArray{T, N}}) where {T, N} = AbstractArray{T, M} where M

```

---

<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: [January 20, 2018, 10:25am UTC](https://discourse.julialang.org/t/stripping-parameter-from-parametric-types/8293/11 "2018-01-20T10:25:21Z")

</div>

May you give an example where my attempted solution above fails to do the desired task?

---

<div class="post-metadata">

### Author: ![jameson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jameson/32/23_2.png) [@jameson](https://discourse.julialang.org/u/jameson)
#### Post date: [January 24, 2018, 4:05am UTC](https://discourse.julialang.org/t/stripping-parameter-from-parametric-types/8293/12 "2018-01-24T04:05:02Z")

</div>

This is a frequently asked question, so I’ve included my reply in the manual: [https://docs.julialang.org/en/latest/manual/methods/#Extracting-the-type-parameter-from-a-super-type-1](https://docs.julialang.org/en/latest/manual/methods/#Extracting-the-type-parameter-from-a-super-type-1)

---

<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: [January 24, 2018, 4:20am UTC](https://discourse.julialang.org/t/stripping-parameter-from-parametric-types/8293/13 "2018-01-24T04:20:45Z")

</div>

Thanks for adding that section. I see the point in:

> However, it is not hard to construct cases where this will fail:
> 
> `struct BitVector <: AbstractArray{Bool, 1}; end`
> 
> Here we have created a type BitVector which has no parameters, but where the element-type is still fully specified, with T equal to Bool!

But how is this related to stripping the last specified parameter in a parametric type? In this case, `BitVector` is not parametric in its own right so it will be just returned back. Your comment is probably related to the bigger goal of the OP. I was just curious if my attempted solution could fail to do what I wanted it to do, regardless of whether or not it is the best way to reach the OP’s goal (clearly not from your comment).

---

<div class="post-metadata">

### Author: ![jameson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jameson/32/23_2.png) [@jameson](https://discourse.julialang.org/u/jameson)
#### Post date: [January 24, 2018, 4:49am UTC](https://discourse.julialang.org/t/stripping-parameter-from-parametric-types/8293/14 "2018-01-24T04:49:53Z")

</div>

“stripping the last specified parameter in a parametric type” is an underspecified operation. There’s perhaps several ways of doing it, but it’s slightly arbitrary to care about _this_ super type compared to any other possible super type. As for that, I would probably go with the following implementation, until someone explained why they wanted to do this particular non-sensical operation:

```julia
supertypeof(x::T) where {T} =
    (isempty(T.parameters) ? supertype(T) : T.name.wrapper{T.parameters[1:(end - 1)]...})

```

---

<div class="post-metadata">

### Author: ![e3c6](https://avatars.discourse-cdn.com/v4/letter/e/e79b87/32.png) [@e3c6](https://discourse.julialang.org/u/e3c6)
#### Post date: [April 21, 2020, 1:30pm UTC](https://discourse.julialang.org/t/stripping-parameter-from-parametric-types/8293/15 "2020-04-21T13:30:58Z")

</div>

What about stripping _all_ type parameters? So going from `Array{T,N}` to `Array`, but generically (for other types besides `Array`). That is well-defined, right?

---

<div class="post-metadata">

### Author: ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)
#### Post date: [April 22, 2020, 10:46am UTC](https://discourse.julialang.org/t/stripping-parameter-from-parametric-types/8293/16 "2020-04-22T10:46:38Z")

</div>

You can use `Base.typename` in recent versions of Julia

---

<div class="post-metadata">

### Author: ![liuyxpp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/liuyxpp/32/9870_2.png) [@liuyxpp](https://discourse.julialang.org/u/liuyxpp)
#### Post date: [April 9, 2022, 12:56pm UTC](https://discourse.julialang.org/t/stripping-parameter-from-parametric-types/8293/17 "2022-04-09T12:56:55Z")

</div>

`Base.typename` returns a `Core.TypeName` object. To get the bare type, you still have to use `Base.typename(T).wrapper`. It seems useing `T.name.wrapper` is more straightforward.

---

<div class="post-metadata">

### Author: ![e3c6](https://avatars.discourse-cdn.com/v4/letter/e/e79b87/32.png) [@e3c6](https://discourse.julialang.org/u/e3c6)
#### Post date: [September 25, 2022, 6:10pm UTC](https://discourse.julialang.org/t/stripping-parameter-from-parametric-types/8293/18 "2022-09-25T18:10:39Z")

</div>

It seems tacky to use `T.name.wrapper`. Is this a stable API?

---

<div class="post-metadata">

### Author: ![milankl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milankl/32/4198_2.png) [@milankl](https://discourse.julialang.org/u/milankl)
#### Post date: [April 19, 2024, 6:13pm UTC](https://discourse.julialang.org/t/stripping-parameter-from-parametric-types/8293/19 "2024-04-19T18:13:42Z")

</div>

I’m hitting this issue so often when dealing with custom arrays that have parameters that I usually just define manually the `nonparametric_type`

```julia
struct Custom1Array{P1, P2, P3} <: AbstractCustomArray
nonparametric_type(::Type{Custom1Array}) = Custom1Array

struct Custom2Array{P1, P2, P3} <: AbstractCustomArray
nonparametric_type(::Type{Custom2Array}) = Custom2Array

```

and then I can write a function like

```julia
function f(A::CustomArray, args...) where {CustomArray<:AbstractCustomArray}
    CustomArray_ = nonparametric_type(CustomArray)
    # now construct new array with parameters P1, P2, P3 depending on args...
    return CustomArray_{P1, P2, P3}(...)
end

```

for all `<:AbstractCustomArray`. Adding a `nonparametric_type` method for a new type is really not a burden compared to the type definition itself and yes `T.name.wrapper` feels somewhat hacky.
