# The Broadcasting API and small Unions

**URL:** <https://discourse.julialang.org/t/the-broadcasting-api-and-small-unions/10896>\
**Category:** General Usage\
**Created:** [May 15, 2018, 12:49am UTC](https://discourse.julialang.org/t/the-broadcasting-api-and-small-unions/10896 "2018-05-15T00:49:40Z")\
**Posts on this page:** 8\
**Page:** 1

<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:** [May 15, 2018, 12:49am UTC](https://discourse.julialang.org/t/the-broadcasting-api-and-small-unions/10896/1 "2018-05-15T00:49:40Z")

</div>

After trying some near examples and the docs, I have not yet made the Broadcasting API do this. More explicit guidance is appreciated.

```julia
abstract type OtherAbstractFloat <: AbstractFloat end
primitive type Float64a <: OtherAbstractFloat 64 end
primitive type Float64b <: OtherAbstractFloat 64 end

const Float64s = Union{Float64, Float64a, Float64b}
const MaybeFloat64s = Union{Missing, Float64, Float64a, Float64b}

# Float64a, Float64b work like Float64; show with '\^a', '\^b'

Base.Float64(x::T) where {T<:OtherAbstractFloat} = reinterpret(Float64, x)
Float64a(x::Float64) = reinterpret(Float64a, x)
Float64b(x::Float64) = reinterpret(Float64b, x)

Base.show(io::IO, x::Float64a) = print(io, string(Float64(x),"ᵃ"))
Base.show(io::IO, x::Float64b) = print(io, string(Float64(x),"ᵇ"))

square(x::T) where {T<:AbstractFloat} = T(Float64(x)^2)
square(x::Missing) = missing

testvec1 = Float64s[Float64(1.0), Float64a(2.0), Float64b(3.0)]
testvec2 = MaybeFloat64s[Float64(1.0), Float64a(2.0), missing]

# this happens without using the Broadcasting API

square.(testvec1)
3-element Array{AbstractFloat,1}:
 1.0 
 4.0ᵃ
 9.0ᵇ

square.(testvec2)
3-element Array{Any,1}:
 1.0     
 4.0ᵃ    
  missing

# I want to obtain

square.(testvec1) # 3-element Array{Float64s,1}
3-element Array{Union{Float64, Float64a, Float64b},1}:
 1.0 
 4.0ᵃ
 9.0ᵇ

square.(testvec2) # 3-element Array{MaybeFloat64s,1}
3-element Array{Union{Missing, Float64, Float64a, Float64b},1}:
 1.0     
 4.0ᵃ    
  missing

```

---

<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:** [May 15, 2018, 9:16am UTC](https://discourse.julialang.org/t/the-broadcasting-api-and-small-unions/10896/2 "2018-05-15T09:16:41Z")

</div>

Seems that when the number of elements in the union goes over two, inference falls back to Any.

```julia
julia> Base._return_type(square, Tuple{Union{Missing, Float64}})
Union{Missing, Float64}

julia> Base._return_type(square, Tuple{Union{Missing, Float64, Float64a}})
Any

```

---

<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:** [May 15, 2018, 9:26am UTC](https://discourse.julialang.org/t/the-broadcasting-api-and-small-unions/10896/3 "2018-05-15T09:26:43Z")

</div>

That seems inconsistent with all the effort done to make working with small unions (up to four types) performant. As I understand it, most of that work is about handling vectors and arrays of elements typed as small unions. I thought that the Broadcasting API could be used to get the result I seek by using it to make this logic happen:

```julia

function Base.Broadcast.broadcast(fn, x::AbstractArray{T,N}) where 
                                                             {N, T<:Float64s}
    result = similar(x)
    @inbounds @simd for idx in eachindex(view(x, axes(x)...,))
        result[idx] = fn(x[idx])
    end
    return result
end

```

---

<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:** [May 15, 2018, 9:28am UTC](https://discourse.julialang.org/t/the-broadcasting-api-and-small-unions/10896/4 "2018-05-15T09:28:19Z")

</div>

Not taking into a account `fn` when allocating the `result` doesn’t seem like it would work. What if `fn` was `x -> convert(Int, x)`?

A workaround is:

```julia
res = similar(testvec2);
res .= square.(testvec2)

```

---

<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:** [May 15, 2018, 9:31am UTC](https://discourse.julialang.org/t/the-broadcasting-api-and-small-unions/10896/5 "2018-05-15T09:31:12Z")

</div>

Yes, that is true. In my application I need to make arrays of small unions of Float64-like primitive types respond to floating point math functions just as arrays of Float64s do. So I know the result types for each group of functions I “delegate”.

That workaround looks very helpful. Is there a way to use it with a specialized Broadcast Style and `broadcast_similar` so that a client app could write `squares = square.(testvec1)` and generally `res = mathfunction.(testvec1)`?

---

<div class="post-metadata">

**Author:** ![Bernard\_GODARD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bernard_godard/32/4155_2.png) [@Bernard\_GODARD](https://discourse.julialang.org/u/Bernard_GODARD)\
**Post date:** [May 15, 2018, 10:23am UTC](https://discourse.julialang.org/t/the-broadcasting-api-and-small-unions/10896/6 "2018-05-15T10:23:41Z")

</div>

In Julia 0.6:

```julia
julia> square(x::Int)=x*x
square (generic function with 2 methods)

julia> Base._return_type(square, Tuple{Union{Int64, Float64}})
Union{Float64, Int64}

julia> arr=Union{Int64,Float64}[1,2.0]
2-element Array{Union{Float64, Int64},1}:
 1  
 2.0

julia> square.(arr)
2-element Array{Real,1}:
 1  
 4.0

```

---

<div class="post-metadata">

**Author:** ![nalimilan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nalimilan/32/147_2.png) [@nalimilan](https://discourse.julialang.org/u/nalimilan)\
**Post date:** [May 15, 2018, 1:20pm UTC](https://discourse.julialang.org/t/the-broadcasting-api-and-small-unions/10896/7 "2018-05-15T13:20:32Z")

</div>

Ref. [https://github.com/JuliaLang/julia/issues/27106](https://github.com/JuliaLang/julia/issues/27106).

---

<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:** [May 15, 2018, 1:27pm UTC](https://discourse.julialang.org/t/the-broadcasting-api-and-small-unions/10896/8 "2018-05-15T13:27:27Z")

</div>

FWIW, I was wrong here, `_return_types` is only used if the return type is concrete.
