-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Specialize map(T, ::AbstractRange) for more range types to preserve the result as a range #40746
Conversation
Co-authored-by: Simeon Schaub <[email protected]>
Edit: This comment is retained for context, but this PR does not implement broadcasting anymore as this might be breaking as things currently stand. Using julia> struct Position <: Integer
val::Int
end
julia> Position(x::Position) = x Previously: julia> Position.(1:3)
3-element Vector{Position}:
Position(1)
Position(2)
Position(3) After this PR: julia> Position.(1:3)
ERROR: <= not defined for Position In this case perhaps such a change would be too breaking, and this PR might only focus on the additional map methods for ranges? Incidentally it'd be better for the map to work as well: julia> map(Position, 1:3)
ERROR: <= not defined for Position The optimistic approach would be to get the map to work, although I'm not sure if this may be done in general. |
map(::Type{Int}, r::IdentityUnitRange) = r | ||
# For IdentityUnitRange{<:OneTo}, the map may be evaluated correctly in Base | ||
# We pop the parent range as the result may not always be representable as an IdentityUnitRange | ||
map(::Type{T}, r::IdentityUnitRange{<:OneTo}) where {T<:Real} = map(T, axes1(r)) | ||
# this method is for ambiguity resolution | ||
map(::Type{Int}, r::IdentityUnitRange{<:OneTo}) = r |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For r::IdentityUnitRange
, given that IdentityUnitRange(r.indices) === r
, we could possibly use the deconstruct-and-then-construct alternative to solve ambiguity:
map(::Type{Int}, r::IdentityUnitRange) = r | |
# For IdentityUnitRange{<:OneTo}, the map may be evaluated correctly in Base | |
# We pop the parent range as the result may not always be representable as an IdentityUnitRange | |
map(::Type{T}, r::IdentityUnitRange{<:OneTo}) where {T<:Real} = map(T, axes1(r)) | |
# this method is for ambiguity resolution | |
map(::Type{Int}, r::IdentityUnitRange{<:OneTo}) = r | |
Base.map(::Type{T}, r::IdentityUnitRange) where {T<:Real} = identity_or_map(T, axes1(r)) | |
identity_or_map(::Type{Int}, r::AbstractUnitRange) = IdentityUnitRange(r) # the caller `map` thus becomes `identity` | |
identity_or_map(::Type{T}, r::AbstractUnitRange) = map(T, r) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will stack overflow as axes1(r) === r
for Base.IdentityUnitRange
if the parent range is not a Base.OneTo
julia> r = Base.IdentityUnitRange(2:3)
Base.IdentityUnitRange(2:3)
julia> map(Int32, r)
ERROR: StackOverflowError:
Broadcasting a type over a range currently converts the output to anArray
. After this PR, when numerical types are broadcast over ranges of numbers, the output may remain a rangeEdit: As broadcasting seemed complicated (the failure is described in #40746 (comment)), this PR only implements
map
for more range types. NowThis also adds a
CartesianIndex
constructor that enables