Generalizing Dot Syntax to Broadcast Operators for Arbitrary Types

I am trying to make the dot syntax for broadcasting work for a type which I defined.

As an example,

mutable struct A
a
b
end

function broadcast!(f, dest::A, x::A, y::A)
dest.a = f(x.a, y.a)
dest.b = f(x.b, y.b)
end

could make the following expression well defined (x, y of type A)

x .+= y

by calling

broadcast!(+, x, x, y)

But after trying this out, I needed to define “iterate(::A)” to make x .+ y work. I did that by defining:

function iterate(x::A{T}, state::S = 1) where {T, S<:Integer}
if state == 1
return (x.a, 2)
elseif state == 2
return (x.b, 3)
else
return nothing
end
end

But then, the result of (x .+ y) is again an array, not an object of type A. Is there any way I can generalize the “.” behavior for my own types?

I believe this could make dealing with complex types a lot easier.

Check out Customizing broadcasting.

4 Likes

I hadn’t seen that, thank you for the pointer!

I am posting how to make my example work. Because I am not sub-typing any Array (as in the documentation), I needed to implement “broadcastable” and a binary “BroadcastStyle” constructor to make broadcasting “A” instances with other types (e.g. floats) work. Thanks again for the link!

import Base:BroadcastStyle

function Base.size(x::A{T}) where {T}
return (2,)
end

function Base.getindex(x::A{T}, inds) where {T}
xa = [x.a, x.b]
return xa[inds]
end

function Base.setindex!(x::A{T}, X, inds) where {T}
xa = [x.a, x.b]
xa[inds] = X
x.a = xa[1]
x.b = xa[2]
end

struct MyStyle <: BroadcastStyle end

Base.BroadcastStyle(::Type{<:A{T}}) where {T} = MyStyle()

function Base.similar(bc::Broadcast.Broadcasted{MyStyle}, ::Type{T}) where {T}
return A{T}(T(0), T(0))
end

function Base.broadcastable(x::A{T}) where {T}
return x
end

Base.BroadcastStyle(::MyStyle, ::BroadcastStyle) where {T} = MyStyle()

x = A(1., 2.)
y = A(3., 4.)

println(BroadcastStyle(typeof(x)))
println(Base.broadcastable(x))

println(x .+ y)
println(x .+ .2)
println(.2 .+ x)