Is it possible to express a type relationship between arrays with different numbers of dimensions?

What I really want to be able to do is express a type such as:

struct Foo{T,N}
b::Array{T,N+1} # doesn't work but I hope it conveys what I want

The important part for me is that the b field has one more dimension than the a field regardless of how many dimensions a has. I suppose I could add another type parameter for the number of dimensions of b and enforce the relationship in an inner constructor, but that is unwieldy for me, because then any other container or type that uses Foo also has to know about that type parameter. Plus it just feels unsatisfying to have to add an additional type parameter when it’s derived from another. Is there any way to accomplish something like this? As far as I can tell I don’t think there is, but figured I would see if anyone knows about something clever I’m not aware of.

1 Like

How about b::Vector{Arrray{T,N}} It’s slightly different than what you want, but might get the right result.

I’m not that this will fully solve your problem, but you can always omit the N+1 in the type declaration and enforce it with an inner constructor. As in:

struct Foo{T,N}

Do you lose anything important that way?

Yeah usually that’s good enough, but in this case I actually do need the memory layout of the higher dimensional array.

That does technically work I guess, but it won’t be type stable which is unfortunate.

The standard solution here is to write

struct Foo{T,N,M}

and then check in the constructor that M == N+1.


Okay, that’s what I thought I had to do. Do you think there is any possibility that there will ever be support for more expressiveness with value types? It seems that at the moment basically every restriction one might want to assert on them has to be handled outside of the type domain: either in inner constructors for structs, or in the body of a function for function arguments. From what I have been able to find it seems that even restricting N to be an Int value has to be done in the constructor. It seems to me that it would be reasonable for values to retain some of their basic relationships to one another even when they are being used as types.

Possibly. It’s a tricky language design problem though. There’s an issue about it somewhere on GitHub. Something about delayed evaluation of types in struct declarations.

Well that led me down a rabbit hole. Things along this line seem to have come up a bunch of times. I think you’re referring to

Isn’t this type piracy?


Why would you think it is?

Well, the spelling, for one thing!


Yes, because that’s the only place where it can possibly matter. For existing objects which are of a parametrized type, the compiler does not need to care about these restrictions.

The constructor is the right place to verify these restrictions, or compute extra types. This design is elegant because it does not require a special syntax for restrictions on types, but subsumes them under all calculations and restrictions the type needs.

This is such a common question that there should be a FAQ entry about it — I will write one today.


There’s also . It doesn’t actually change the fact that your type will have a parameter for N and a parameter for N + 1, but it at least lets you avoid having to write out that parameter most of the time.

PR for FAQ:



I helped bring this package up to date for Julia v1.0 a while back, I use it in some of my packages for the same purpose as the OP asks about

Thank you for making my day :joy::joy:

I’m not convinced it’s terribly elegant. If I want to restrict T to be some sort of Float I write Foo{T<:AbstractFloat,N}. That sort of restriction is expressed in the type domain via a type hierarchy. If I want to restrict N to be a particular sort of value type I have to check that restraint myself in a constructor.

They are both restrictions on what sorts of types I can use here, but only one of them can be expressed in the type domain. I can see restrictions on what sort of types these parameters can be by looking at the first line of a struct definition unless I have value types. Julia enforces those restrictions on other types, but for value types I have to enforce those restrictions manually in my code. That doesn’t feel elegant to me.

Subtype relation is special because it is fundamental to a lot of things, most importantly dispatch.

All kinds of restrictions can be enforced in Julia, it’s just that subtypes have a special syntax. You could do

struct Foo{T}
    function Foo(x::T) where T
        if !(T <: AbstractFloat)
            throw(ArgumentError("look, I really need a float here and $T isn't one"))

and get pretty much the same behavior as

struct Foo{T<:AbstractFloat}

just without some bells and whistles.

Elegance is of course always a subjective term for programming language design. Personally, I find the current setup elegant because of parsimony: no extra syntax needs to be introduced, and checking these kind of restrictions is pretty much orthogonal to everything else that happens to instances of this type after construction.

Eg consider a hypothetical

struct Foo{T,N}

Suppose I want to retrieve the computed type parameter, without hardcoding the actual computation in my code, for which there is a very standard pattern with explicit parameters. Should we introduce special syntax for this too?

Or consider relations between parameters which you can test for, but not compute (because the relation is not a function, or it is expensive/nontrivial to invert). Instead of

struct Foo{T,S}
    function Foo(a::T, b::S) where {T,S}
        check_Foo_types(T, S) || error("baaad types")
        new{T,S}(a, b)

you would need to introduce a syntax to specify check_Foo_types somewhere, and still use the constructor for other checks.