Content Copy (.= Operator) for Composite Types (structs)?


#1

For arrays, we have a beautiful new .= operator that copies the contents of the right to the left.

For structs, this is not working:

julia> mutable struct Point; x; y; end#struct

julia> p= Point(2,3)
Point(2, 3)

julia> n= Point(5,10)
Point(5, 10)

julia> n .= p
ERROR: MethodError: no method matching broadcast!(::Base.#identity, ::Point, ::Point)
Closest candidates are:
  broadcast!(::Any, ::AbstractArray, ::Any, ::Any...) where N at broadcast.jl:206
  broadcast!(::Base.#identity, ::Array{T,N}, ::Array{S,N}) where {T, S, N} at broadcast.jl:18
  broadcast!(::Base.#identity, ::AbstractArray, ::Number) at broadcast.jl:22
  ...

would this be a good language addition? what is a good way to define this myself? the following seems fairly ugly and becomes unwieldy for large structs.

copycontents(l,r) = ( l.x=r.x; l.y=r.y; l )

/iaw


#2

The dot syntax invokes the broadcasting interface. A key design decision here is whether (mutable) structs should be considered containers over which one can broadcast.

This can make sense where the operation is sufficiently generic so that it works for all fields. I am skeptical about enabling this in general, since I usually use structures for heterogeneous collections.

The .= is a special case, but I would rather implement a method for copy!. This would also sidestep the whole promotion machinery for broadcasting; provided one does not want somestruct .= somearray and things like that.


#3

You can just do

Base.broadcast!(::typeof(identity), dest::Point, src::Point) = (dest.x=src.x; dest.y=src.y; dest)
n .= p;

If you really, really want you could try something like

@generated function Base.broadcast!(::typeof(identity), dest::T, src::T) where T
...
end

But I think that this default would be too dangerous (if your mutable has mutable fields, how deep do you copy? What about pointer fields? Handles to system resources?).


#4

thank you, tamas and foobar. I am beginning to appreciate the devils in the detail here. yes, this should not be a default. maybe an easier way to allow users to state that this is what they want? not sure.