Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Ref behave as a 0-dimensional array in broadcast #18965

Merged
merged 2 commits into from
Dec 21, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
--------------------

Expand Down Expand Up @@ -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
Expand Down
22 changes: 16 additions & 6 deletions base/broadcast.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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...))
Expand All @@ -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
Expand Down Expand Up @@ -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]

Expand Down Expand Up @@ -301,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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing close paren?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is in the following line.

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
Expand Down Expand Up @@ -351,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"
Expand Down
2 changes: 1 addition & 1 deletion doc/src/manual/arrays.md
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down
7 changes: 7 additions & 0 deletions test/broadcast.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cute, I didn't realize that fill could be used to create a 0-dimensional array like this

@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]]