# Specifying output container type based on input container

**URL:** <https://discourse.julialang.org/t/specifying-output-container-type-based-on-input-container/96197>\
**Category:** General Usage\
**Tags:** question\
**Created:** [March 16, 2023, 4:51pm UTC](https://discourse.julialang.org/t/specifying-output-container-type-based-on-input-container/96197 "2023-03-16T16:51:40Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [March 16, 2023, 4:51pm UTC](https://discourse.julialang.org/t/specifying-output-container-type-based-on-input-container/96197/1 "2023-03-16T16:51:40Z")

</div>

I have a question about generic functions which is probably something simple I am missing. Let’s say I have a function `f` defined as follows:

```julia
function f(x::A)::AbstractArray{T, N-1} where {T<:Real, N, A<:AbstractArray{T, N}}
    dropdims(sum(x, dims=(1,)), dims=(1,))
end

```

This function takes an arbitrary array `x` as input, and specifies to the compiler that an array will be returned `::AbstractArray{T,N-1}`, i.e., with the same parameters `T`, and 1 fewer dimension.

However, is there a way I can specify that an array of the same container type as `x` will always be returned? For example, if `x` is an `Array{T,2}`, I want to indicate that an `Array{T,1}` will also be returned - not just any `AbstractArray`. Similar for `StaticArrays`, etc.

I tried the obviously incorrect expression

```julia
function f(x::A)::A{T,N-1} where {T<:Real, N, A<:AbstractArray{T, N}}
    dropdims(sum(x, dims=(1,)), dims=(1,))
end

```

which does not work. Is there a way to do this?

* * *

I should also specify - for this simple function I am sure the compiler can figure it out. But for more complex functions in my codebase I find it helped to indicate the output type… so perhaps indicating the correct container type will help as well.

Thanks!  
Miles

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [March 16, 2023, 5:10pm UTC](https://discourse.julialang.org/t/specifying-output-container-type-based-on-input-container/96197/2 "2023-03-16T17:10:41Z")

</div>

Here’s a hacky attempt to inform the compiler about the container type (using [How to get the container type of a container?](https://discourse.julialang.org/t/how-to-get-the-container-type-of-a-container/20253)):

```julia
constructor_of(::Type{T}) where T =
    getfield(T.name.module, Symbol(T.name.name))

function f(x::A) where {T<:Real, N, A<:AbstractArray{T, N}}
   dropdims(sum(x, dims=(1,)), dims=(1,))::constructor_of(A){T,N-1}
end

```

where you would wrap the entire function block with `::constructor_of(A){T,N-1}`.

But surely there’s a way to do it directly in the function signature?

* * *

One other attempt:

```julia
function f(x::A)::(A.name.wrapper){T,N-1} where {T<:Real, N, A<:AbstractArray{T, N}}
   dropdims(sum(x, dims=(1,)), dims=(1,))
end

```

this feels illegal though. Not sure if `A.name.wrapper` is stable or not?

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [March 16, 2023, 5:52pm UTC](https://discourse.julialang.org/t/specifying-output-container-type-based-on-input-container/96197/3 "2023-03-16T17:52:21Z")

</div>

> [@MilesCranmer](#):
>
> But surely there’s a way to do it directly in the function signature?

No. There is no API for specifying what the element type of an output array (or its dimensionality) ought to be because that’s not something inherent to the type system you can specify for dispatch (which doesn’t include the _return type_ either way - that’s only part of what is inferred as an optimization).

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [March 16, 2023, 5:58pm UTC](https://discourse.julialang.org/t/specifying-output-container-type-based-on-input-container/96197/4 "2023-03-16T17:58:04Z")

</div>

> There is no API for specifying what the element type of an output array (or its dimensionality) ought to be because that’s not something inherent to the type system you can specify for dispatch

Sorry, not sure I follow. Are you stating this as a terminology thing, or are you actually saying the effect of `::` has no effect on the function? Because, for example:

```julia
f(x::AbstractArray{Float64})::AbstractArray{Float32} = x

f(randn(Float64, 100)) # this is now of type Array{Float32}

```

Regardless of this finer point, the reason I want to specify container type is simply to help out the compiler for functions where the output type is ambiguous, and it might not be able to infer it by itself.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [March 16, 2023, 6:03pm UTC](https://discourse.julialang.org/t/specifying-output-container-type-based-on-input-container/96197/5 "2023-03-16T18:03:19Z")

</div>

that syntax is doing conversion

```julia
julia> Meta.@lower f(x::AbstractArray{Float64})::AbstractArray{Float32} = x
:($(Expr(:thunk, CodeInfo(
    @ none within `top-level scope`
1 ─ $(Expr(:thunk, CodeInfo(
    @ none within `top-level scope`
1 ─ return $(Expr(:method, :f))
)))
│ $(Expr(:method, :f))
│ %3 = Core.Typeof(f)
│ %4 = Core.apply_type(AbstractArray, Float64)
│ %5 = Core.svec(%3, %4)
│ %6 = Core.svec()
│ %7 = Core.svec(%5, %6, $(QuoteNode(:(#= REPL[1]:1 =#))))
│ $(Expr(:method, :f, :(%7), CodeInfo(
    @ REPL[1]:1 within `none`
1 ─ %1 = Core.apply_type(AbstractArray, Float32)
│ %2 = Base.convert(%1, x)
│ %3 = Core.typeassert(%2, %1)
└── return %3

```

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [March 16, 2023, 6:10pm UTC](https://discourse.julialang.org/t/specifying-output-container-type-based-on-input-container/96197/6 "2023-03-16T18:10:43Z")

</div>

Yes, I know this, sorry if I wasn’t clear. Of course I could always manually wrap `convert((A.name.wrapper){T,N-1}, ...)` around my function block, it’s just ugly. And the other thing about the `f(...)::T` syntax I like is it acts as a form of documentation to other users.

I am basically looking for a cleaner way to specify it in the signature without a hacky solution like `f(x::A)::(A.name.wrapper){T,N-1} where ...`. If nothing else exists I guess I can go with that.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [March 16, 2023, 6:14pm UTC](https://discourse.julialang.org/t/specifying-output-container-type-based-on-input-container/96197/7 "2023-03-16T18:14:21Z")

</div>

because `convert` is not free, it may not be a good idea because of performance, I don’t know if you want correctness or performance or simply an API guarantee you think would be nice to have.

In the correctness + performance case, when you have total control, I do something like this:

> <https://github.com/JuliaHEP/UnROOT.jl/blob/146fe2447147f5e56430f006e230ba610f4f5b31/src/RNTuple/fieldcolumn_reading.jl#L71-L79>

this is doing a `typeassert`, which makes sure I get what I expected and conversion never happens (when it’s transferred to a typed buffer container which needs type prediction ahead of time). But if you don’t have total control, it’s hard to say.

I would think CUDA.jl-world has similar problem and they may have a solution utility

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [March 16, 2023, 6:23pm UTC](https://discourse.julialang.org/t/specifying-output-container-type-based-on-input-container/96197/8 "2023-03-16T18:23:02Z")

</div>

Thanks. I guess there is no built-in syntax to do it at the function signature level? Some of the functions I am dealing with have multiple return statements so it could get ugly quickly

Btw, all of my functions already satisfy the type I am expecting; it is just sometimes the compiler can’t figure it out in the locations the function is being called. i.e., the `::(A.name.wrapper){T,N-1}` syntax should not impact performance as it wouldn’t be doing conversions, it would just tell the compiler the return type. (But there’s no cleaner way to write this, I guess)

```julia
julia> @code_llvm convert(Array{Float64}, randn(Float64, 100))
; @ array.jl:617 within `convert`
define nonnull {}* @julia_convert_1423({}* readonly %0, {}* nonnull align 16 dereferenceable(40) %1) #0 {
top:
  ret {}* %1
}

```

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [March 16, 2023, 6:29pm UTC](https://discourse.julialang.org/t/specifying-output-container-type-based-on-input-container/96197/9 "2023-03-16T18:29:23Z")

</div>

right, you need to attached `::T` not at the function definition level because that’s a convert, you need it at

```julia
return res::T

```

to make it a type assert, and “get the concrete container type of the \<:AbstractArray” is not a well defined thing in the type system unfortunately

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [March 16, 2023, 6:41pm UTC](https://discourse.julialang.org/t/specifying-output-container-type-based-on-input-container/96197/10 "2023-03-16T18:41:33Z")

</div>

They are identical if the type is correct though, right?

e.g., signature level:

```bash
julia -e 'function g(x::A)::(A.name.wrapper{T,N-1}) where {T,N,A<:AbstractArray{T,N}}; dropdims(x, dims=(1,)); end; x = ones(32, 1); import InteractiveUtils: @code_llvm; @code_llvm g(x)' \
    2>&1 > signature_level.txt

```

Function level:

```bash
julia -e 'function g(x::A) where {T,N,A<:AbstractArray{T,N}}; dropdims(x, dims=(1,))::(A.name.wrapper{T,N-1}); end; x = ones(32, 1); import InteractiveUtils: @code_llvm; @code_llvm g(x)' \
    2>&1 > function_level.txt

```

The diff is just different addresses:

```llvm
< store atomic i64 140599633651680, i64* %15 unordered, align 8
---
> store atomic i64 139832940386272, i64* %15 unordered, align 8
45c45
< store {}* inttoptr (i64 140599707586240 to {}*), {}** %16, align 8
---
> store {}* inttoptr (i64 139833014320832 to {}*), {}** %16, align 8
93c93
< store atomic i64 140599633764176, i64* %28 unordered, align 8
---
> store atomic i64 139832940498768, i64* %28 unordered, align 8
97c97
< %30 = call nonnull {}* inttoptr (i64 140600165136976 to {}* ({}*, {}*, {}*)*)({}* inttoptr (i64 140599635100832 to {}*), {}* nonnull %0, {}* nonnull %26)
---
> %30 = call nonnull {}* inttoptr (i64 139833471871568 to {}* ({}*, {}*, {}*)*)({}* inttoptr (i64 139832941835424 to {}*), {}* nonnull %0, {}* nonnull %26)

```

I think it’s nicer when you have multiple return statements, and also for documentation if a user is looking at the signature, maybe. I wish there was cleaner syntax though…

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [March 16, 2023, 7:13pm UTC](https://discourse.julialang.org/t/specifying-output-container-type-based-on-input-container/96197/11 "2023-03-16T19:13:48Z")

</div>

typeassert would error if it doesn’t work, convert may silently cost you performance. again, I guess it depends on your goal

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [March 16, 2023, 10:33pm UTC](https://discourse.julialang.org/t/specifying-output-container-type-based-on-input-container/96197/12 "2023-03-16T22:33:39Z")

</div>

I see, that makes sense to me. Thanks!

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [March 17, 2023, 4:51am UTC](https://discourse.julialang.org/t/specifying-output-container-type-based-on-input-container/96197/13 "2023-03-17T04:51:46Z")

</div>

> [@MilesCranmer](#):
>
> ```julia
> constructor_of(::Type{T}) where T =
> getfield(T.name.module, Symbol(T.name.name))
> 
> ```

This is a more refined version (from [ConstructionBase.jl](https://github.com/JuliaObjects/ConstructionBase.jl/blob/master/src/ConstructionBase.jl#L29-L31)) which completely avoids Julia internals:

```julia
@generated function constructorof(::Type{T}) where T
    getfield(parentmodule(T), nameof(T))
end

```

I think ultimately the issue is that, for diagonal types like `f(x::A)::A where A`, when `f` is called the type variable `A` will be concrete and fully parameterized; before you can change some parameters, you first need to shed some by climbing up to a non-concrete `UnionAll` type.

> [@MilesCranmer](#):
>
> the reason I want to specify container type is simply to help out the compiler for functions where the output type is ambiguous

Without this type annotation/conversion, `f`’s output type is being correctly inferred on my machine. I don’t think there’s any need for concern one way or the other, but are you sure this is the point in your codebase where type stability is being lost?

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [March 20, 2023, 4:49am UTC](https://discourse.julialang.org/t/specifying-output-container-type-based-on-input-container/96197/14 "2023-03-20T04:49:01Z")

</div>

Thanks!

> Without this type annotation/conversion, f’s output type is being correctly inferred on my machine. I don’t think there’s any need for concern one way or the other, but are you sure this is the point in your codebase where type stability is being lost?

Yeah. The tricky thing with my codebase [SymbolicRegression.jl](https://github.com/MilesCranmer/SymbolicRegression.jl) is that it is set up to allow arbitrary user-defined operators, loss functions, and constraints. However, sometimes user-defined operators introduce their own type stability for whatever reason (a lot of new Julia users are introduced via the [PySR](https://github.com/MilesCranmer/PySR) frontend, wanting to customize things for their problem), so I have noticed that it helps a lot if I just enforce type stability on their behalf. Then, the user won’t experience a weird slow-down and have to learn these advanced concepts in Julia just to use my library efficiently.

Right now SymbolicRegression.jl only allows for scalar operators, but I’m slowly expanding type constraints to allow for vector operators. So that’s where my question about specifying container types comes from.

---

<div class="post-metadata">

**Author:** ![marius311](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marius311/32/3953_2.png) [@marius311](https://discourse.julialang.org/u/marius311)\
**Post date:** [March 20, 2023, 5:44am UTC](https://discourse.julialang.org/t/specifying-output-container-type-based-on-input-container/96197/15 "2023-03-20T05:44:46Z")

</div>

Maybe another strategy is to use `Core.Compiler.return_type` or `Test.@inferred` to warn or disallow the user from introducing these type instabilities at all. Would lead them to correcting internal instabilities which presumably would make the code even faster than just annotating the return type for them, although would be more work on their end, so certainly a tradeoff.
