Overload broadcasting for custom struct?

Hello!

I have a struct defined as:

struct T3{T}
           x::T
           y::T
           z::T
end

I want to overload it such that when I write:

T3(1,1,1) .* 5 = T3(5,5,5)

But I do not know how to overload “.*”. Can anyone help?

Kind regards

Here is the specification of the interface: https://docs.julialang.org/en/v1/manual/interfaces/#man-interfaces-broadcasting-1.

However, I would say that in general customizing broadcasting is an advanced topic. For example if you want to have a look how much code was needed to add broadcasting to DataFrames.jl you can have a look here: https://github.com/JuliaData/DataFrames.jl/blob/master/src/other/broadcasting.jl.

If do not exactly understand what you want to achieve.

If you define the * operator for a T3{T} like this:

struct T3{T}
           x::T
           y::T
           z::T
end
import Base.*
function (*)(t3::T3{T}, n::Number) where {T}
    return T3{T}(t3.x*n,t3.y*n,t3.z*n)
end  

Then you can write:


julia> t=T3{Float64}(3,4,5)
T3{Float64}(3.0, 4.0, 5.0)

julia> t*5
T3{Float64}(15.0, 20.0, 25.0)

This can be broadcasted for a collection of t3:


julia> vt=[T3{Float64}(1,2,3),T3{Float64}(4,5,8),T3{Float64}(7,8,9)]
3-element Array{T3{Float64},1}:
 T3{Float64}(1.0, 2.0, 3.0)
 T3{Float64}(4.0, 5.0, 8.0)
 T3{Float64}(7.0, 8.0, 9.0)

julia> vt.*=5
3-element Array{T3{Float64},1}:
 T3{Float64}(5.0, 10.0, 15.0)
 T3{Float64}(20.0, 25.0, 40.0)
 T3{Float64}(35.0, 40.0, 45.0)


1 Like

Broadcasting might be useful to define if @Ahmed_Salih wanted to take advantage of fusion in broadcasting (but as I have commented - this is an advanced topic so probably not the first thing to start with).

1 Like

Thanks @LaurentPlagne, that works for me, thanks for showing me how to use it as well!

@bkamins it was a bit more advanced than I thought, but I need to learn somehow :slight_smile: Fun to know this is possible in Julia

@LaurentPlagne just curious, is it possible to make it so that the order of multiplication does not matter?

It allows me to do T3 * number, but not number * T3

Kind regards

Glad that is useful !
For your second question see the discussion here

2 Likes

Thanks for the explanation! It makes more sense now that not in all cases it is wanted to have commutative properties. I didn’t completely understand the point of having “number as subtype”, but I think I will stick to your approach for now.

Kind regards

Note that it is not too long to add;

 (*)(n::Number, t3::T3{T}) where {T} = t3*n

Concerning the n::Number type anotation, I am not sure that it is idiomatic.
The type annotations are of special interest to organize the dispatch of the methods (as it is the case for the t3::T3{T} argument.

Here, since we do not do something specific with the Numbers, it maybe better to let it without annotations.

You don’t need the type parameter T and the where clause here, since you’re not using it.

2 Likes

Thanx ! It takes time to forgot about the C++ verbosity :smiley:

(*)(n, t3::T3) = t3*n