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

Define machinery so that Some can be used for broadcast #35778

Closed
wants to merge 11 commits into from
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ New language features
* The compiler optimization level can now be set per-module using the experimental macro
`Base.Experimental.@optlevel n`. For code that is not performance-critical, setting
this to 0 or 1 can provide significant latency improvements ([#34896]).
* `Some`containers now support broadcast as zero dimensional immutable containers. `Some(x)`
should be preferred to `Ref(x)` when you wish to exempt `x` from broadcasting ([#35778]).

Language changes
----------------
Expand Down
2 changes: 2 additions & 0 deletions base/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ include("broadcast.jl")
using .Broadcast
using .Broadcast: broadcasted, broadcasted_kwsyntax, materialize, materialize!

include("somebroadcast.jl")

# missing values
include("missing.jl")

Expand Down
2 changes: 2 additions & 0 deletions base/some.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
A wrapper type used in `Union{Some{T}, Nothing}` to distinguish between the absence
of a value ([`nothing`](@ref)) and the presence of a `nothing` value (i.e. `Some(nothing)`).

`Some` is also used in broadcasting to treat it's enclosed value as a scalar.
Copy link
Member

Choose a reason for hiding this comment

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

Maybe more accurate to say

Suggested change
`Some` is also used in broadcasting to treat it's enclosed value as a scalar.
`Some` is also used in broadcasting to broadcast a single value to all axes.

? Though I see that a similar wording is already used in Ref.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I feel like that suggestion is less likely to be understood. However, maybe not everyone knows the word "scalar" either.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe it's fine as-is if we also explain the actual interface it implements (i.e., it is a 0-dim iterable that supports indexing).

Copy link
Contributor

Choose a reason for hiding this comment

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

This should say its rather than it's in the original formulation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks Yuri!


Use [`something`](@ref) to access the value wrapped by a `Some` object.
"""
struct Some{T}
Expand Down
18 changes: 18 additions & 0 deletions base/somebroadcast.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#Methods some Some can broadcast
getindex(s::Some) = s.value
getindex(s::Some, ::CartesianIndex{0}) = s.value

iterate(s::Some) = (s.value, nothing)
iterate( ::Some, s) = nothing

ndims(::Some) = 0
ndims(::Type{<:Some}) = 0

length(::Some) = 1
size(::Some) = ()
axes(::Some) = ()

IteratorSize(::Type{<:Some}) = HasShape{0}()
Broadcast.broadcastable(s::Some) = s

eltype(::Type{Some{T}}) where {T} = T
7 changes: 2 additions & 5 deletions doc/src/manual/arrays.md
Original file line number Diff line number Diff line change
Expand Up @@ -947,12 +947,9 @@ julia> string.(1:3, ". ", ["First", "Second", "Third"])

Sometimes, you want a container (like an array) that would normally participate in broadcast to be "protected"
from broadcast's behavior of iterating over all of its elements. By placing it inside another container
(like a single element [`Tuple`](@ref)) broadcast will treat it as a single value.
(we recommend [`Some`](@ref)), broadcast will treat it as a single value.
```jldoctest
julia> ([1, 2, 3], [4, 5, 6]) .+ ([1, 2, 3],)
([2, 4, 6], [5, 7, 9])

julia> ([1, 2, 3], [4, 5, 6]) .+ tuple([1, 2, 3])
julia> ([1, 2, 3], [4, 5, 6]) .+ Some([1, 2, 3])
([2, 4, 6], [5, 7, 9])
```

Expand Down
11 changes: 11 additions & 0 deletions test/some.jl
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,14 @@ using Base: notnothing
# isnothing()
@test !isnothing(1)
@test isnothing(nothing)

#Eltype
@test eltype(Some{Int}) == Int
@test eltype(Some(1)) == Int

# Broadcast with Some
@testset "Some Broadcast" begin
@test Some(1) .+ 1 == 2
@test Some([1, 2]) .+ [[1, 2,], [3, 4]] == [[2, 4], [4, 6]]
@test isa.(Some([1,2,3]), [Array, Dict, Int]) == [true, false, false]
end