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

deprecate unsafe_length for length #40382

Merged
merged 4 commits into from
Jul 2, 2021
Merged

deprecate unsafe_length for length #40382

merged 4 commits into from
Jul 2, 2021

Conversation

vtjnash
Copy link
Sponsor Member

@vtjnash vtjnash commented Apr 6, 2021

This seems to be a fairly arbitrary case for throwing exceptions, when the user might often use this value in arithmetic afterwards (e.g. see searchsorted), which is not checked. It leads to awkward complexity in the API however, where it may be unclear which function to reach for, with no particular justification for why a particular usage is "safe". And it may inhibit optimization and performance due to the additional checks and error cases (and is not even entirely type-stable).

Performance seems to be basically identical:

julia> @btime length($(Ref(1:3:10))[])
  4.413 ns (0 allocations: 0 bytes)
julia> @btime length($(Ref(1:3:10))[])
  4.482 ns (0 allocations: 0 bytes)

@vtjnash vtjnash added the triage This should be discussed on a triage call label Apr 6, 2021
@JeffBezanson JeffBezanson added the arrays [a, r, r, a, y, s] label Apr 6, 2021
@JeffBezanson
Copy link
Sponsor Member

Very nice to eliminate these ugly functions. Triage is concerned about what checks we should have though. We discussed checking on construction whether a range will have a correct length, and moving the error there.

@mbauman mbauman requested a review from timholy April 22, 2021 18:46
@JeffBezanson JeffBezanson removed the triage This should be discussed on a triage call label May 6, 2021
@vtjnash vtjnash added the triage This should be discussed on a triage call label May 27, 2021
@vtjnash
Copy link
Sponsor Member Author

vtjnash commented May 27, 2021

triage thought this was a reasonable change, but that we should keep the current version around as checked_length in the same module as the other checked_math functions

@vtjnash vtjnash removed the triage This should be discussed on a triage call label May 27, 2021
base/deprecated.jl Outdated Show resolved Hide resolved
@vtjnash vtjnash added needs docs Documentation for this change is required needs news A NEWS entry is required for this change needs tests Unit tests are required for this change and removed needs docs Documentation for this change is required needs news A NEWS entry is required for this change needs tests Unit tests are required for this change labels Jun 5, 2021
This seems to be a fairly arbitrary case for throwing exceptions, when
the user might often use this value in arithmetic afterwards, which is
not checked. It leads to awkward complexity in the API however, where it
may be unclear which function to reach for, with no particular
justification for why a particular usage is "safe". And it inhibits
optimization and performance due to the additional checks and error
cases (and is not even entirely type-stable).
@vtjnash
Copy link
Sponsor Member Author

vtjnash commented Jun 9, 2021

@JeffBezanson this should be ready to go now. It removes checking for overflow in length for Union{Int,UInt,Int64,UInt64,Int128,UInt128}, and adds checking for all types in Base.Checked.checked_length (the types Union{Int8, UInt8, Int16, UInt16, Int32, UInt32} are defined to not to overflow through promotion to Int). It is also a bit more consistent about the units of the computations, since (b - a + s) / s and (b - a) / s + one are mathematically equivalently, but could have different units, and we were using them interchangeably (this showed up on the added tests).

@vtjnash vtjnash added the merge me PR is reviewed. Merge when all tests are passing label Jun 21, 2021
@JeffBezanson JeffBezanson changed the title RFC: deprecate unsafe_length for length? deprecate unsafe_length for length Jun 30, 2021
@vtjnash vtjnash merged commit 3eefaf0 into master Jul 2, 2021
@vtjnash vtjnash deleted the jn/unsafe_length branch July 2, 2021 14:28
@DilumAluthge DilumAluthge removed the merge me PR is reviewed. Merge when all tests are passing label Jul 4, 2021
johanmon pushed a commit to johanmon/julia that referenced this pull request Jul 5, 2021
This seems to be a fairly arbitrary case for throwing exceptions, when
the user might often use this value in arithmetic afterwards, which is
not checked. It leads to awkward complexity in the API however, where it
may be unclear which function to reach for, with no particular
justification for why a particular usage is "safe". And it inhibits
optimization and performance due to the additional checks and error
cases (and is not even entirely type-stable).
@giordano
Copy link
Contributor

After this pull request

julia> using Unitful

julia> length(1u"m":2u"m":0u"m")
0 m

KristofferC pushed a commit that referenced this pull request Jul 26, 2021
This seems to be a fairly arbitrary case for throwing exceptions, when
the user might often use this value in arithmetic afterwards, which is
not checked. It leads to awkward complexity in the API however, where it
may be unclear which function to reach for, with no particular
justification for why a particular usage is "safe". And it inhibits
optimization and performance due to the additional checks and error
cases (and is not even entirely type-stable).

(cherry picked from commit 3eefaf0)
github-merge-queue bot pushed a commit that referenced this pull request Jul 15, 2023
I noticed
[here](#50467 (comment))
that `lastindex(x::Base.OneTo)` is not simply `x.stop`. This PR performs
that optimization and many more by assuming `size` always returns
positive numbers.
```
julia> @code_native lastindex(Base.OneTo(5)) # master
        .section        __TEXT,__text,regular,pure_instructions
        .build_version macos, 13, 0
        .globl  _julia_lastindex_81             ; -- Begin function julia_lastindex_81
        .p2align        2
_julia_lastindex_81:                    ; @julia_lastindex_81
; ┌ @ abstractarray.jl:423 within `lastindex`
; %bb.0:                                ; %top
; │┌ @ abstractarray.jl:386 within `eachindex`
; ││┌ @ abstractarray.jl:134 within `axes1`
; │││┌ @ range.jl:708 within `axes`
; ││││┌ @ range.jl:471 within `oneto`
; │││││┌ @ range.jl:469 within `OneTo` @ range.jl:454
; ││││││┌ @ promotion.jl:532 within `max`
; │││││││┌ @ int.jl:83 within `<`
        ldr     x8, [x0]
; │││││││└
; │││││││┌ @ essentials.jl:642 within `ifelse`
        cmp     x8, #0
        csel    x0, x8, xzr, gt
; │└└└└└└└
        ret
; └
                                        ; -- End function
.subsections_via_symbols

julia> @code_native lastindex(Base.OneTo(5)) # pr
        .section        __TEXT,__text,regular,pure_instructions
        .build_version macos, 13, 0
        .globl  _julia_lastindex_13253          ; -- Begin function julia_lastindex_13253
        .p2align        2
_julia_lastindex_13253:                 ; @julia_lastindex_13253
; ┌ @ abstractarray.jl:423 within `lastindex`
; %bb.0:                                ; %top
        ldr     x0, [x0]
        ret
; └
                                        ; -- End function
.subsections_via_symbols
```

Also removed `axes(r::AbstractRange) = (oneto(length(r)),)` (added in
#40382, @vtjnash) as redundant with the general `axes` method.

The obvious downside here is that if someone defines an object with
negative size, its axes will include Base.OneTo with negative stop. I
think that is acceptable, but if not, we can gate this optimization to a
set of known types (all AbstractArray types defined in Base should have
non-negative size)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
arrays [a, r, r, a, y, s]
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants