# Tricky "too many parameters for type" error

Dear Julia community,

I get a “too many parameters for type” error that I cannot really understand.

Luckily, I have been able (after some effort) to isolate the issue to a very small reproducer:

``````module AAA

abstract type IterCellValue{R} end
abstract type Map{S,M,T,N} end
const IterCellMap{S,M,T,N,R} = IterCellValue{R} where R <:Map{S,M,T,N}
const Foo{S,T,N,R} = IterCellMap{S,1,T,N,R}

struct Bar{S,T,N,R} <: Foo{S,T,N,R} end # error here, help please!!

end # module

``````

I would say that `Foo` has 4 type parameters. What I am missing?

============= EDIT ==============

I found myself the solution. Replace the first const declaration by an abstract type declaration. Namely:

``````module AAA

abstract type IterCellValue{R} end
abstract type Map{S,M,T,N} end
abstract type IterCellMap{S,M,T,N,R<:Map{S,M,T,N}} <: IterCellValue{R} end
const Foo{S,T,N,R} = IterCellMap{S,1,T,N,R}

struct Bar{S,T,N,R} <: Foo{S,T,N,R} end # works!

end # module
``````

However, I would like to know if it is the expected behavior the error I got in the first version.

Thanks for helping!

`struct Bar{S,T,N,R} <: IterCellMap{S,1,T,N,R} end` does not throw any errors. Does that help?

In this case `Foo` (and `IterCellMap`) only have one type parameter. When you put the line

``````const IterCellMap{S,M,T,N,R} = IterCellValue{R} where R <:Map{S,M,T,N}
``````

Julia interprets this as

``````const IterCellMap = IterCellValue{R} where R<:Map{S,M,T,N} where N where T where M where S
``````

i.e., `IterCellMap` is just the same as `IterCellValue` with a single parameter `R`. And likewise for `Foo`

3 Likes

Thanks for the anwser. Makes sense.

What surprises me is that I was able to go quite far with this wrong definition in my code until i found the error

1 Like

I have been trying to better understand the problem. I have figured out an explanation, but I would be very grateful if someone can confirm whether it is correct.

``````abstract type Foo{A} end
const Bar = Foo{A} where A<:AbstractArray{T,N} where N where T
const BarVec = Bar{T,1,A} where A where T
struct MyBar{T} <: BarVec{T,Vector{T}} end # error: too many parameters for type
``````

The problem is with line

``````const BarVec = Bar{T,1,A} where A where T
``````

My explanation is that this line gets converted into

``````const BarVec = (Foo{A} where A<:AbstractArray{T,N} where N where T) where A where T
``````

then into

``````# The info about A<:AbstractArray{T,N} is lost
const BarVec = (Foo{A} where A where N where T) where A where T
``````

and finally into

``````const BarVec = Foo{A} where A
``````

since `Foo` does not depend on `T` nor `N`

Is this interpretation correct?

why the restriction `A<:AbstractArray{T,N}` is lost in this process?

Thanks again for the help!
Francesc

Not quite correct; the info about `A <: AbstractArray` is not lost. Consider the following

``````julia> struct Foo{A} ; a::A ; end

julia> const Bar = Foo{A} where A <: AbstractArray  # note the where N where T is unnecessary
Foo{A} where A<:AbstractArray

julia> Bar{typeof([1])}([1])
Foo{Array{Int64,1}}([1])

julia> Bar{typeof(1)}(1)  # not an AbstractArray
ERROR: TypeError: in Type, in A, expected A<:AbstractArray, got Type{Int64}
Stacktrace:
[1] top-level scope at none:0

julia> Foo{typeof(1)}(1)  # directly with Foo (doesn't have the subtyping relation imposed)
Foo{Int64}(1)
``````

Note that `AbstractArray{T,N} where N where T` is equivalent to `AbstractArray` on its own.

1 Like

Yes, sure. But he info about `A <: AbstractArray` is lost in `BarVec`, right? This is what I meant.

No, the problem is that your `BarVec` line doesn’t make sense since `Bar` only has a single type parameter `A` (though that `A` is restricted to be an `AbstractArray`).

I think you are trying to achieve the following

``````julia> const BarVec = Bar{A} where A <: AbstractArray{T, 1} where T
Foo{A} where A<:AbstractArray{T,1} where T

julia> BarVec{Int64}{Vector{Int64}}([1])
Foo{Array{Int64,1}}([1])
``````

but note that the constructor becomes more annoying to specify (multiple sets of braces). Personally I wouldn’t enforce multi-layered type constraints like this but instead use a constructor to enforce it.

1 Like

``````#1
const Bar = Foo{A} where A<:AbstractArray{T,N} where N where T

#2
const Bar = Foo{A} where A<:AbstractArray

#3
const Bar = Foo{A} where {A<:AbstractArray{T,N} where N where T}
``````

#2 and #3 are quivalent, but not #1, right?

Yes, you are right, I had forgotten that subtlety. As such, try

``````julia> struct Foo{A} ; a::A ; end

julia> const Bar = Foo{A} where {T, N, A <: AbstractArray{T, N}}
Foo{A} where A<:AbstractArray{T,N} where N where T

julia> const BarVec = Bar{T, 1} where T
Foo{A} where A<:AbstractArray{T,1} where T

julia> a = [1,2,3]
3-element Array{Int64,1}:
1
2
3

julia> BarVec{eltype(a),typeof(a)}(a)
Foo{Array{Int64,1}}([1, 2, 3])
``````

OK, I’ve worked out what the problem is (sorry, I was getting slightly confused)

on this line the `where A` seems to remove the subtyping relationship; simply omitting the `A` at the end of the parameter list (and the corresponding `where A`) causes the subtyping relationship to be preserved. This is why my example (which leaves the explicit `A` out of definition of `BarVec`) works but yours doesn’t.

1 Like

Yes, this is what puzzles me.

Is this the expected behavior or it is a bug?

I have vague memories of seeing a GitHub issue that mentions this problem but I can’t find it now. I don’t think it’s the intended behaviour but I suspect that it isn’t a high priority one to fix (particularly as it can be worked around as per my example).

1 Like