# Broadcasting for a new type & passing a value by ref

**URL:** <https://discourse.julialang.org/t/broadcasting-for-a-new-type-passing-a-value-by-ref/70255>\
**Category:** New to Julia\
**Tags:** question, broadcast\
**Created:** [October 23, 2021, 6:46am UTC](https://discourse.julialang.org/t/broadcasting-for-a-new-type-passing-a-value-by-ref/70255 "2021-10-23T06:46:33Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![dodoplus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dodoplus/32/30148_2.png) [@dodoplus](https://discourse.julialang.org/u/dodoplus)\
**Post date:** [October 23, 2021, 6:46am UTC](https://discourse.julialang.org/t/broadcasting-for-a-new-type-passing-a-value-by-ref/70255/1 "2021-10-23T06:46:33Z")

</div>

Hi,

I have a struct as follows:

```julia
struct P
    df::DataFrame
end

```

where the `DataFrame` contains labels (`qs`) & prior probabilities (`probs`). I’ve implemented multiplication & normalization:

```julia
Base.:(*)(p::P, v) = P(DataFrame(qs=p.df.qs, probs=p.df.probs .* v))
normalize!(p::P) = p.df.probs = p.df.probs ./ sum(p.df.probs)

```

which allows Bayesian updating:

```julia
prior = P(DataFrame(qs = ["heads", "tail"], probs=[0.5, 0.5]) # illustrative. Not how it's done
likelihood = [0.75, 0.5]
posterior = prior * likelihood
normalize!(posterior)

```

Now for the question: say I want to create an `update` function that will update a probability distribution with new data (likelihood):

```julia
# Does not work
function update!(p::P, likelihood)
  p *= likehood
  normalize!(p)
end

```

This doesn’t work because although `p` is passed by reference, `p *= likelihood` is actually translated to `p = p * likelihood`, which results in a new `p` being allocated.

OK, fine. As the multiplication is really a broadcast operation - what about supporting broadcast for the new type, so I can write:

```julia
p .*= likelihood

```

This (if it works) should result in modification of the elements of the `DataFrame`, which should preserve the pass-by-ref semantics.

Trouble is, I can’t figure out how to actually implement the broadcasting interface. I’m lost in a sea of `broadcastable`, and `BroadcastStyle`s…

How do I define a simple broadcast interface for this type? Is there any other way of to get `update!` to work?

(obviously, I can just write:

```julia
p.probs .*= likelihood

```

or define a function that will do that for me:

```julia
mul!(p::P, likelihood) = p.probs .*= likelihood

```

but that’s a cop out)

Thanks  
DD

---

<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:** [October 23, 2021, 8:01am UTC](https://discourse.julialang.org/t/broadcasting-for-a-new-type-passing-a-value-by-ref/70255/2 "2021-10-23T08:01:20Z")

</div>

Let’s start with the interface:

[https://docs.julialang.org/en/v1/manual/interfaces/#man-interfaces-broadcasting](https://docs.julialang.org/en/v1/manual/interfaces/#man-interfaces-broadcasting)

From here, you can see “Methods to implement”:

- `Base.BroadcastStyle`
- `Base.similar`

So that is the absolute minimum you need. The former is just a trait with a type _you define_ to allow for dispatching to your methods, the latter tells the broadcasting machinery how to allocate an object of your type (with given element type). In addition to the above, you’ll also want to [define `copyto!` for your broadcast style](https://docs.julialang.org/en/v1/manual/interfaces/#extending-in-place-broadcast-2) for in-place broadcasting.

I’d recommend giving this talk a watch, it has an introduction to broadcasting a custom array in the second half:

[![](https://global.discourse-cdn.com/julialang/original/3X/0/6/06b71d551368fc5bd6fdf3b9541952ba9c96799b.jpeg "An introduction to high performance custom arrays | Matt Bauman") ](https://www.youtube.com/watch?v=jS9eouMJf_Y)

---

<div class="post-metadata">

**Author:** ![dodoplus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dodoplus/32/30148_2.png) [@dodoplus](https://discourse.julialang.org/u/dodoplus)\
**Post date:** [October 23, 2021, 11:22am UTC](https://discourse.julialang.org/t/broadcasting-for-a-new-type-passing-a-value-by-ref/70255/3 "2021-10-23T11:22:08Z")

</div>

Thanks, the lecture was pretty helpful.

I’ve progressed and now have:

```julia
using DataFrames
struct P
    df::DataFrame
end
P(q,p) = P(DataFrame(qs=q, ps=p))
Base.size(p::P) = size(p.df)
Base.getindex(p::P, i) = p.df[findfirst(==(i), p.df.qs), :ps]
Base.show(io::IO, m::MIME{Symbol("text/html")}, p::P) = Base.show(io, m, p.df)
Base.ndims(n::Type{P}) = 1
Base.Broadcast.broadcasted(::typeof(*), p::P, x) = P(p.df.qs, p.df.ps .* x)

```

I can now do:

```julia
g=P(["heads", "tails"], [0.5, 0.5])
g = g .* [0.2, 0.5]

```

However, the following doesn’t work:

```julia
g .*= [0.2, 0.5]

```

Julia complains about

```julia
MethodError: no method matching copyto!(::P, ::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}, typeof(identity), Tuple{P}})

```

How do I define this method correctly?

```julia
function Base.copyto!(d::P, bc::Base.Broadcast.Broadcasted)
   # ???
end

```

Regards,  
DD

---

<div class="post-metadata">

**Author:** ![dodoplus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dodoplus/32/30148_2.png) [@dodoplus](https://discourse.julialang.org/u/dodoplus)\
**Post date:** [October 23, 2021, 11:39am UTC](https://discourse.julialang.org/t/broadcasting-for-a-new-type-passing-a-value-by-ref/70255/4 "2021-10-23T11:39:52Z")

</div>

EDIT:  
the following seems to work:

```julia
function Base.copyto!(d::P, bc::Base.Broadcast.Broadcasted)
    if bc.f == identity
        d.df.ps = bc.args[1].df.ps
    else
       # ???
    end
    return d
end

g=P(["heads", "tails"], [0.5, 0.5])
f(g) = g .*= [0.5, 0.5]
f(g)
g

```

This seems to work and I get the expected result:

```julia
2 rows × 2 columns

qs	ps
String	Float64
1	heads	0.25
2	tails	0.25

```

However, I have no idea what goes into the `else` clause. In addition, this solution involves too much copying.
