Skip to content

Commit

Permalink
range(; stop) and range(; length)
Browse files Browse the repository at this point in the history
  • Loading branch information
mkitti committed Feb 16, 2021
1 parent 1bc7f43 commit 358d1a4
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 7 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Standard library changes
* `count` and `findall` now accept an `AbstractChar` argument to search for a character in a string ([#38675]).
* `range` now supports the `range(start, stop)` and `range(start, stop, length)` methods ([#39228]).
* `range` now supports `start` as an optional keyword argument ([#38041]).
* `range` accepts either `stop` or `length` as a sole keyword argument ([#39241])
* `islowercase` and `isuppercase` are now compliant with the Unicode lower/uppercase categories ([#38574]).
* `iseven` and `isodd` functions now support non-`Integer` numeric types ([#38976]).
* `escape_string` can now receive a collection of characters in the keyword
Expand Down
44 changes: 38 additions & 6 deletions base/range.jl
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@ Construct a specialized array with evenly spaced elements and optimized storage
Mathematically a range is uniquely determined by any three of `start`, `step`, `stop` and `length`.
Valid invocations of range are:
* Call `range` with any three of `start`, `step`, `stop`, `length`.
* Call `range` with two of `start`, `stop`, `length`. In this case `step` will be assumed
to be one. If both arguments are Integers, a [`UnitRange`](@ref) will be returned.
* Call `range` with two of `start`, `stop`, `length`. In this case `step` will be assumed to be one.
* Call `range` with one of `stop` or `length`. `start` and `step` will be assumed to be one.
See Extended Help for additional details on the returned type.
# Examples
```jldoctest
Expand Down Expand Up @@ -87,6 +89,15 @@ julia> range(stop=10, step=1, length=5)
julia> range(start=1, step=1, stop=10)
1:1:10
julia> range(; length = 10)
Base.OneTo(10)
julia> range(; stop = 6)
Base.OneTo(6)
julia> range(; stop = 6.5)
1.0:1.0:6.0
```
If `length` is not specified and `stop - start` is not an integer multiple of `step`, a range that ends before `stop` will be produced.
```jldoctest
Expand All @@ -101,8 +112,21 @@ To avoid this induced overhead, see the [`LinRange`](@ref) constructor.
`stop` as a positional argument requires at least Julia 1.1.
!!! compat "Julia 1.7"
The versions without keyword arguments and `start` as a keyword argument
require at least Julia 1.7.
The versions without keyword arguments, `start` as a keyword argument,
`stop` as a sole keyword argument, or length as a sole keyword argument
requires at least Julia 1.7.
# Extended Help
`range` will produce a `Base.OneTo` when the arguments are Integers and
* Only `length` is provided
* Only `stop` is provided
`range` will produce a `UnitRange` when the arguments are Integers and
* Only `start` and `stop` are provided
* Only `length` and `stop` are provided
A `UnitRange` is not produced if `step` is provided even if specified as one.
"""
function range end

Expand All @@ -115,8 +139,8 @@ range(;start=nothing, stop=nothing, length::Union{Integer, Nothing}=nothing, ste
_range(start, step, stop, length)

_range(start::Nothing, step::Nothing, stop::Nothing, len::Nothing) = range_error(start, step, stop, len)
_range(start::Nothing, step::Nothing, stop::Nothing, len::Any ) = range_error(start, step, stop, len)
_range(start::Nothing, step::Nothing, stop::Any , len::Nothing) = range_error(start, step, stop, len)
_range(start::Nothing, step::Nothing, stop::Nothing, len::Any ) = range_length(len)
_range(start::Nothing, step::Nothing, stop::Any , len::Nothing) = range_stop(stop)
_range(start::Nothing, step::Nothing, stop::Any , len::Any ) = range_stop_length(stop, len)
_range(start::Nothing, step::Any , stop::Nothing, len::Nothing) = range_error(start, step, stop, len)
_range(start::Nothing, step::Any , stop::Nothing, len::Any ) = range_error(start, step, stop, len)
Expand All @@ -131,6 +155,14 @@ _range(start::Any , step::Any , stop::Nothing, len::Any ) = range_start
_range(start::Any , step::Any , stop::Any , len::Nothing) = range_start_step_stop(start, step, stop)
_range(start::Any , step::Any , stop::Any , len::Any ) = range_error(start, step, stop, len)

# Length as the only argument
range_length(len::Integer) = OneTo(len)

# Stop as the only argument
range_stop(stop) = range_start_stop(oneunit(start), stop)
range_stop(stop::Integer) = range_length(stop)

# Stop and length as the only argument
range_stop_length(a::Real, len::Integer) = UnitRange{typeof(a)}(oftype(a, a-len+1), a)
range_stop_length(a::AbstractFloat, len::Integer) = range_step_stop_length(oftype(a, 1), a, len)
range_stop_length(a, len::Integer) = range_step_stop_length(oftype(a-a, 1), a, len)
Expand Down
20 changes: 19 additions & 1 deletion test/ranges.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,20 @@
# the next ones use ==, because it changes the eltype
@test r == range(first(r), last(r), length(r) )
@test r == range(start=first(r), stop=last(r), length=length(r))
@test r === range( stop=last(r), length=length(r))

r = 1:5
o = Base.OneTo(5)
let start=first(r), step=step(r), stop=last(r), length=length(r)
@test o === range(; stop )
@test o === range(; length)
@test r === range(; start, stop )
@test r === range(; stop, length)
# the next three lines uses ==, because it changes the eltype
@test r == range(; start, stop, length)
@test r == range(; start, step, length)
@test r == range(; stop=Float64(stop))
end

for T = (Int8, Rational{Int16}, UInt32, Float64, Char)
@test typeof(range(start=T(5), length=3)) === typeof(range(stop=T(5), length=3))
Expand Down Expand Up @@ -1450,8 +1464,12 @@ end
@test_throws ArgumentError range(1)
@test_throws ArgumentError range(nothing)
@test_throws ArgumentError range(1, step=4)
@test_throws ArgumentError range(nothing, length=2)
@test_throws ArgumentError range(; step=1, length=6)
@test_throws ArgumentError range(; step=2, stop=7.5)
@test_throws ArgumentError range(1.0, step=0.25, stop=2.0, length=5)
@test_throws ArgumentError range(; stop=nothing)
@test_throws ArgumentError range(; length=nothing)
@test_throws TypeError range(; length=5.5)
end

@testset "issue #23300#issuecomment-371575548" begin
Expand Down

0 comments on commit 358d1a4

Please sign in to comment.