From 0351aa0dfd671b65111e8ca98838dcef8718bfa6 Mon Sep 17 00:00:00 2001 From: pabloferz Date: Sat, 22 Oct 2016 08:27:56 -0500 Subject: [PATCH 1/2] Make Ref behave as a scalar wrapper for broadcast --- base/broadcast.jl | 4 ++++ test/broadcast.jl | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/base/broadcast.jl b/base/broadcast.jl index c459832d7d13c..841d97b9b1b3b 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -27,7 +27,9 @@ end # logic for deciding the resulting container type containertype(x) = containertype(typeof(x)) containertype(::Type) = Any +containertype{T<:Ptr}(::Type{T}) = Any containertype{T<:Tuple}(::Type{T}) = Tuple +containertype{T<:Ref}(::Type{T}) = Array containertype{T<:AbstractArray}(::Type{T}) = Array containertype(ct1, ct2) = promote_containertype(containertype(ct1), containertype(ct2)) @inline containertype(ct1, ct2, cts...) = promote_containertype(containertype(ct1), containertype(ct2, cts...)) @@ -46,6 +48,7 @@ broadcast_indices(A) = broadcast_indices(containertype(A), A) broadcast_indices(::Type{Any}, A) = () broadcast_indices(::Type{Tuple}, A) = (OneTo(length(A)),) broadcast_indices(::Type{Array}, A) = indices(A) +broadcast_indices(::Type{Array}, A::Ref) = () @inline broadcast_indices(A, B...) = broadcast_shape((), broadcast_indices(A), map(broadcast_indices, B)...) # shape (i.e., tuple-of-indices) inputs broadcast_shape(shape::Tuple) = shape @@ -118,6 +121,7 @@ map_newindexer(shape, ::Tuple{}) = (), () end Base.@propagate_inbounds _broadcast_getindex(A, I) = _broadcast_getindex(containertype(A), A, I) +Base.@propagate_inbounds _broadcast_getindex(::Type{Array}, A::Ref, I) = A[] Base.@propagate_inbounds _broadcast_getindex(::Type{Any}, A, I) = A Base.@propagate_inbounds _broadcast_getindex(::Any, A, I) = A[I] diff --git a/test/broadcast.jl b/test/broadcast.jl index d6cf1a3c0985b..41d40c1c2909d 100644 --- a/test/broadcast.jl +++ b/test/broadcast.jl @@ -366,3 +366,10 @@ let g() = (a = 1; Base.Broadcast._broadcast_type(x -> x + a, 1.0)) @test @inferred(g()) === Float64 end + +# Ref as 0-dimensional array for broadcast +@test (-).(C_NULL, C_NULL)::UInt == 0 +@test (+).(1, Ref(2)) == fill(3) +@test (+).(Ref(1), Ref(2)) == fill(3) +@test (+).([[0,2], [1,3]], [1,-1]) == [[1,3], [0,2]] +@test (+).([[0,2], [1,3]], Ref{Vector{Int}}([1,-1])) == [[1,1], [2,2]] From 986d5752fdb1a9d9e282bb281cc439d2ea69b501 Mon Sep 17 00:00:00 2001 From: pabloferz Date: Sat, 22 Oct 2016 18:13:22 -0500 Subject: [PATCH 2/2] News and docs for #18965 --- NEWS.md | 4 ++++ base/broadcast.jl | 18 ++++++++++++------ doc/src/manual/arrays.md | 2 +- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/NEWS.md b/NEWS.md index 6f7c04aec3095..ba9a8ba8856d9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -47,6 +47,9 @@ This section lists changes that do not have deprecation warnings. `broadcast` calls (see above) and produce an `Array`. If you want a `Range` result, use `+` and `*`, etcetera ([#17623]). + * `broadcast` now treats `Ref` (except for `Ptr`) arguments as 0-dimensional + arrays ([#18965]). + Library improvements -------------------- @@ -749,6 +752,7 @@ Language tooling improvements [#18628]: https://github.com/JuliaLang/julia/issues/18628 [#18839]: https://github.com/JuliaLang/julia/issues/18839 [#18931]: https://github.com/JuliaLang/julia/issues/18931 +[#18965]: https://github.com/JuliaLang/julia/issues/18965 [#18977]: https://github.com/JuliaLang/julia/issues/18977 [#19018]: https://github.com/JuliaLang/julia/issues/19018 [#19233]: https://github.com/JuliaLang/julia/issues/19233 diff --git a/base/broadcast.jl b/base/broadcast.jl index 841d97b9b1b3b..40908df116f13 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -305,15 +305,16 @@ end """ broadcast(f, As...) -Broadcasts the arrays, tuples and/or scalars `As` to a container of the +Broadcasts the arrays, tuples, `Ref` and/or scalars `As` to a container of the appropriate type and dimensions. In this context, anything that is not a -subtype of `AbstractArray` or `Tuple` is considered a scalar. The resulting -container is established by the following rules: +subtype of `AbstractArray`, `Ref` (except for `Ptr`s) or `Tuple` is considered +a scalar. The resulting container is established by the following rules: - If all the arguments are scalars, it returns a scalar. - If the arguments are tuples and zero or more scalars, it returns a tuple. - - If there is at least an array in the arguments, it returns an array - (and treats tuples as 1-dimensional arrays) expanding singleton dimensions. + - If there is at least an array or a `Ref` in the arguments, it returns an array + (and treats any `Ref` as a 0-dimensional array of its contents and any tuple + as a 1-dimensional array) expanding singleton dimensions. A special syntax exists for broadcasting: `f.(args...)` is equivalent to `broadcast(f, args...)`, and nested `f.(g.(args...))` calls are fused into a @@ -355,11 +356,16 @@ julia> abs.((1, -2)) julia> broadcast(+, 1.0, (0, -2.0)) (1.0,-1.0) -julia> broadcast(+, 1.0, (0, -2.0), [1]) +julia> broadcast(+, 1.0, (0, -2.0), Ref(1)) 2-element Array{Float64,1}: 2.0 0.0 +julia> (+).([[0,2], [1,3]], Ref{Vector{Int}}([1,-1])) +2-element Array{Array{Int64,1},1}: + [1,1] + [2,2] + julia> string.(("one","two","three","four"), ": ", 1:4) 4-element Array{String,1}: "one: 1" diff --git a/doc/src/manual/arrays.md b/doc/src/manual/arrays.md index 4224afe201ffb..a0ced689485e9 100644 --- a/doc/src/manual/arrays.md +++ b/doc/src/manual/arrays.md @@ -475,7 +475,7 @@ is equivalent to `broadcast(f, args...)`, providing a convenient syntax to broad [automatically fuse](@ref man-dot-operators) into a single `broadcast` call. Additionally, [`broadcast()`](@ref) is not limited to arrays (see the function documentation), -it also handles tuples and treats any argument that is not an array or a tuple as a "scalar". +it also handles tuples and treats any argument that is not an array, tuple or `Ref` (except for `Ptr`) as a "scalar". ```julia julia> convert.(Float32, [1, 2])