The current broadcasting behavior is non-intuitive when used with @.
Julia Version 0.7.0-DEV.5222,
Commit 7144b6b816 (2018-05-25 20:23 UTC)
This is a minimal example, stripped down from a real use case.
struct Material
a::Float64
end
chi(m::Material, energy) = m.a / energy
m1 = Material(1.0)
energy = 1.5:0.5:2.5
chi1 = @. chi(m1, energy)
┌ Warning: broadcast will default to iterating over its arguments in the future. Wrap arguments of
│ type `x::Material` with `Ref(x)` to ensure they broadcast as "scalar" elements.
This is probably following
https://github.com/JuliaLang/julia/pull/26435
Replacing m1 with Ref(m1) in the last line, as suggested by the error message, results in an error:
chi1 = @. chi(Ref(m1), energy)
┌ Warning: broadcast will default to iterating over its arguments in the future. Wrap arguments of
│ type `x::Material` with `Ref(x)` to ensure they broadcast as "scalar" elements.
│ caller = ip:0x0
└ @ Core :-1
ERROR: MethodError: no method matching chi(::Base.RefValue{Material}, ::Float64)
Closest candidates are:
chi(::Material, ::Any) at REPL[2]:1
Following the doc and adding
Base.broadcastable(m::Material) = Ref(m)
does help (no warning, no error).
But it this is a very surprising behavior:
by default, a struct
should be considered as a scalar.
I’ll have to read again relevant issues such as
https://github.com/JuliaLang/julia/issues/18379
https://github.com/JuliaLang/julia/issues/18618
for now, it is not clear why broadcasting could not be an opt-in behavior,
with iterators opting-in in their interface definition.
Another take, showing that the Ref()
tip does not work:
f(x, y) = println(x, " ", y)
x = 1:3
@. f(x, Ref(x))
1 Base.RefValue{Int64}(1)
2 Base.RefValue{Int64}(2)
3 Base.RefValue{Int64}(3)
Trying to prepend a $
to prevent broadcasting (like before a function)
did not work either.
@. f(x, $x)
1 1
2 2
3 3