# How to specialize arguments to avoid unions

**URL:** <https://discourse.julialang.org/t/how-to-specialize-arguments-to-avoid-unions/53906>\
**Category:** New to Julia\
**Tags:** question, parametric-types\
**Created:** [January 25, 2021, 1:12pm UTC](https://discourse.julialang.org/t/how-to-specialize-arguments-to-avoid-unions/53906 "2021-01-25T13:12:26Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![nandoconde](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nandoconde/32/19497_2.png) [@nandoconde](https://discourse.julialang.org/u/nandoconde)\
**Post date:** [January 25, 2021, 1:12pm UTC](https://discourse.julialang.org/t/how-to-specialize-arguments-to-avoid-unions/53906/1 "2021-01-25T13:12:27Z")

</div>

Hello everyone!

I am trying to write two functions that accept 3D and 2D arrays that can be either real or complex. The first function receives arguments of one dimension higher than the second function. Then, it iterates over that extra dimension calling the second function for each “slice” of the arguments along that dimension. The purpose of the code is converting S-matrices for many frequencies at given reference impedances for all ports, also at that many frequencies.

The problem is that all arguments can be either Real or Complex arrays and even different between them, although the most common case is that the first argument is complex and the rest are real. How can I write the header of the function to admit Real and Complex arrays without explicitly typing

```julia
CR = Union{Real,Complex}
function S2S(S::Array{T1,3},Za::Array{T2,2},Zb::Array{T3,2}) where {T1 <:CR && T2 <: CR && T3 <: CR}
...
end

```

I leave my current code here. Thanks!

```julia
function S2S(Sₐ::Array{ComplexF64,3},Zₐ::Array{Float64,2},Zᵦ::Array{Float64,2})
    Sᵦ = similar(Sₐ)
    for f in 1:size(Sₐ,3)
        Sᵦ[:,:,f] = S2S(Sₐ[:,:,f],Zₐ[:,f],Zᵦ[:,f])
    end
    return Sᵦ
end

function S2S(Sₐ::Array{ComplexF64,2},Zₐ::Array{Float64,1},Zᵦ::Array{Float64,1})
    U = UniformScaling(size(Sₐ,1))
    G = diagm(sqrt.(Zₐ./Zᵦ))
    Γ = diagm((Zᵦ-Zₐ)./(Zᵦ+Zₐ))
    return Sᵦ = G*inv(U-Sₐ)*(Sₐ-Γ)*inv(U-Sₐ*Γ)*(U-Sₐ)*inv(G)
end

```

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [January 25, 2021, 1:20pm UTC](https://discourse.julialang.org/t/how-to-specialize-arguments-to-avoid-unions/53906/2 "2021-01-25T13:20:44Z")

</div>

Do you really need those type annotations? Why not `AbstractArray` everywhere, or even not annotating at all?

Lyndon White has a nice blog post on “Over-constraining argument types”, it is one of the sections of the post [here](https://www.oxinabox.net/2020/04/19/Julia-Antipatterns.html). Maybe that helps.

---

<div class="post-metadata">

**Author:** ![nandoconde](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nandoconde/32/19497_2.png) [@nandoconde](https://discourse.julialang.org/u/nandoconde)\
**Post date:** [January 25, 2021, 1:33pm UTC](https://discourse.julialang.org/t/how-to-specialize-arguments-to-avoid-unions/53906/3 "2021-01-25T13:33:02Z")

</div>

I do need to type the dimensions so the first function calls the second. I can substitute `AbstractArray` where `Array` is typed, but otherwise, I cannot see how this would help.

Why is better `AbstractArray` than `Array`?

Thanks!

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [January 25, 2021, 1:34pm UTC](https://discourse.julialang.org/t/how-to-specialize-arguments-to-avoid-unions/53906/4 "2021-01-25T13:34:05Z")

</div>

> [@nandoconde](#):
>
> Why is better `AbstractArray` than `Array` ?

It will accept `@views`, for example.

Edit: something like this will be more concise, anyway:

```julia
julia> function g!(x::AbstractArray{T1,3},y::AbstractArray{T2,2}) where {T1,T2 <: Number}
         x = 2*x
         y = 2*y
         nothing
       end
g! (generic function with 1 method)

julia> x = rand(ComplexF64,3,3,3);

julia> y = rand(3,2);

julia> g!(x,y)

```

(adapted to your case, of course)

---

<div class="post-metadata">

**Author:** ![tomerarnon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomerarnon/32/3170_2.png) [@tomerarnon](https://discourse.julialang.org/u/tomerarnon)\
**Post date:** [January 25, 2021, 2:02pm UTC](https://discourse.julialang.org/t/how-to-specialize-arguments-to-avoid-unions/53906/5 "2021-01-25T14:02:47Z")

</div>

With regards to choosing `AbstractArray` rather than `Array`, consider that there are many subtypes of `AbstractArray` that may not appear relevant when first writing your algorithm, but that generalizing to is very convenient (`Adjoint`, `UniformScaling`, `Diagonal`, `StaticArray` just to name a few!).

If the first argument _must_ be a complex number (that is, real arguments are completely not allowed ever), then it makes sense to restrict it. Otherwise, go with `Number` (which already _is_ the supertype of `Real` and `Complex`, so no need to define `CR`). For the other arguments, restricting to `Float64` is almost never a good idea in practice. Should your algorithm really fail if the inputs are integers, or would all of the math “just work” anyway? I would probably consider a signature like this (again, assuming complex is absolutely required for the first one, otherwise I would leave that eltype off as well)

```julia
function S2S(Sₐ::AbstractArray{<:Complex, 3}, Zₐ::AbstractMatrix, Zᵦ::AbstractMatrix)
    ...
end

function S2S(Sₐ::AbstractMatrix{<:Complex}, Zₐ::AbstractVector, Zᵦ::AbstractVector)
    ...
end

```

---

<div class="post-metadata">

**Author:** ![nandoconde](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nandoconde/32/19497_2.png) [@nandoconde](https://discourse.julialang.org/u/nandoconde)\
**Post date:** [January 25, 2021, 4:41pm UTC](https://discourse.julialang.org/t/how-to-specialize-arguments-to-avoid-unions/53906/6 "2021-01-25T16:41:10Z")

</div>

Thanks, super helpful!!

Just the last question: why is it better to have `AbstractMatrix` than `AbstractMatrix{Number}`? Shouldn’t it be better this other way, in order to prevent, for example, matrices of `String`?

---

<div class="post-metadata">

**Author:** ![Jeff\_Emanuel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff_emanuel/32/15440_2.png) [@Jeff\_Emanuel](https://discourse.julialang.org/u/Jeff_Emanuel)\
**Post date:** [January 25, 2021, 4:50pm UTC](https://discourse.julialang.org/t/how-to-specialize-arguments-to-avoid-unions/53906/7 "2021-01-25T16:50:40Z")

</div>

Parametric types are not covariant. Using Matrix{Number} will not match an argument of Matrix{Float64}, for instance. Instead, you should specify Matrix{\<:Number}.

---

<div class="post-metadata">

**Author:** ![nandoconde](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nandoconde/32/19497_2.png) [@nandoconde](https://discourse.julialang.org/u/nandoconde)\
**Post date:** [January 25, 2021, 4:54pm UTC](https://discourse.julialang.org/t/how-to-specialize-arguments-to-avoid-unions/53906/8 "2021-01-25T16:54:14Z")

</div>

Yeah, sorry, I meant to put the `<:` but forgot it.

In any case, is it better for the compiler not to specify the least possible type, or there is no usage and performance penalty?

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [January 25, 2021, 4:56pm UTC](https://discourse.julialang.org/t/how-to-specialize-arguments-to-avoid-unions/53906/9 "2021-01-25T16:56:59Z")

</div>

The annotations of types on function arguments are _only_ for dispatch. It makes no difference whatsoever for performance. The function will be specialized to the given type when executed. This confusion is one of the reasons that make we tend to start annotating everything (the blog post of Lyndon White above is very good in emphasizing that - it discusses the other reasons for using annotations, of course, but performance is not one of those).

---

<div class="post-metadata">

**Author:** ![Jeff\_Emanuel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff_emanuel/32/15440_2.png) [@Jeff\_Emanuel](https://discourse.julialang.org/u/Jeff_Emanuel)\
**Post date:** [January 25, 2021, 5:00pm UTC](https://discourse.julialang.org/t/how-to-specialize-arguments-to-avoid-unions/53906/10 "2021-01-25T17:00:15Z")

</div>

The usage penalty is that you may constrain it to be too narrow and disallow some valid use cases.
