Skip to content

Commit 9daf90a

Browse files
committed
range(; stop) and range(; length)
1 parent 1bc7f43 commit 9daf90a

File tree

3 files changed

+58
-7
lines changed

3 files changed

+58
-7
lines changed

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ Standard library changes
4545
* `count` and `findall` now accept an `AbstractChar` argument to search for a character in a string ([#38675]).
4646
* `range` now supports the `range(start, stop)` and `range(start, stop, length)` methods ([#39228]).
4747
* `range` now supports `start` as an optional keyword argument ([#38041]).
48+
* `range` accepts either `stop` or `length` as a sole keyword argument ([#39241])
4849
* `islowercase` and `isuppercase` are now compliant with the Unicode lower/uppercase categories ([#38574]).
4950
* `iseven` and `isodd` functions now support non-`Integer` numeric types ([#38976]).
5051
* `escape_string` can now receive a collection of characters in the keyword

base/range.jl

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,10 @@ Construct a specialized array with evenly spaced elements and optimized storage
5656
Mathematically a range is uniquely determined by any three of `start`, `step`, `stop` and `length`.
5757
Valid invocations of range are:
5858
* Call `range` with any three of `start`, `step`, `stop`, `length`.
59-
* Call `range` with two of `start`, `stop`, `length`. In this case `step` will be assumed
60-
to be one. If both arguments are Integers, a [`UnitRange`](@ref) will be returned.
59+
* Call `range` with two of `start`, `stop`, `length`. In this case `step` will be assumed to be one.
60+
* Call `range` with one of `stop` or `length`. `start` and `step` will be assumed to be one.
61+
62+
See Extended Help for additional details on the returned type.
6163
6264
# Examples
6365
```jldoctest
@@ -87,6 +89,15 @@ julia> range(stop=10, step=1, length=5)
8789
8890
julia> range(start=1, step=1, stop=10)
8991
1:1:10
92+
93+
julia> range(; length = 10)
94+
Base.OneTo(10)
95+
96+
julia> range(; stop = 6)
97+
Base.OneTo(6)
98+
99+
julia> range(; stop = 6.5)
100+
1.0:1.0:6.0
90101
```
91102
If `length` is not specified and `stop - start` is not an integer multiple of `step`, a range that ends before `stop` will be produced.
92103
```jldoctest
@@ -101,8 +112,21 @@ To avoid this induced overhead, see the [`LinRange`](@ref) constructor.
101112
`stop` as a positional argument requires at least Julia 1.1.
102113
103114
!!! compat "Julia 1.7"
104-
The versions without keyword arguments and `start` as a keyword argument
105-
require at least Julia 1.7.
115+
The versions without keyword arguments, `start` as a keyword argument,
116+
`stop` as a sole keyword argument, or length as a sole keyword argument
117+
requires at least Julia 1.7.
118+
119+
# Extended Help
120+
121+
`range` will produce a `Base.OneTo` when the arguments are Integers and
122+
* Only `length` is provided
123+
* Only `stop` is provided
124+
125+
`range` will produce a `UnitRange` when the arguments are Integers and
126+
* Only `start` and `stop` are provided
127+
* Only `length` and `stop` are provided
128+
129+
A `UnitRange` is not produced if `step` is provided even if specified as one.
106130
"""
107131
function range end
108132

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

117141
_range(start::Nothing, step::Nothing, stop::Nothing, len::Nothing) = range_error(start, step, stop, len)
118-
_range(start::Nothing, step::Nothing, stop::Nothing, len::Any ) = range_error(start, step, stop, len)
119-
_range(start::Nothing, step::Nothing, stop::Any , len::Nothing) = range_error(start, step, stop, len)
142+
_range(start::Nothing, step::Nothing, stop::Nothing, len::Any ) = range_length(len)
143+
_range(start::Nothing, step::Nothing, stop::Any , len::Nothing) = range_stop(stop)
120144
_range(start::Nothing, step::Nothing, stop::Any , len::Any ) = range_stop_length(stop, len)
121145
_range(start::Nothing, step::Any , stop::Nothing, len::Nothing) = range_error(start, step, stop, len)
122146
_range(start::Nothing, step::Any , stop::Nothing, len::Any ) = range_error(start, step, stop, len)
@@ -131,6 +155,14 @@ _range(start::Any , step::Any , stop::Nothing, len::Any ) = range_start
131155
_range(start::Any , step::Any , stop::Any , len::Nothing) = range_start_step_stop(start, step, stop)
132156
_range(start::Any , step::Any , stop::Any , len::Any ) = range_error(start, step, stop, len)
133157

158+
# Length as the only argument
159+
range_length(len::Integer) = OneTo(len)
160+
161+
# Stop as the only argument
162+
range_stop(stop) = range_start_stop(oneunit(stop), stop)
163+
range_stop(stop::Integer) = range_length(stop)
164+
165+
# Stop and length as the only argument
134166
range_stop_length(a::Real, len::Integer) = UnitRange{typeof(a)}(oftype(a, a-len+1), a)
135167
range_stop_length(a::AbstractFloat, len::Integer) = range_step_stop_length(oftype(a, 1), a, len)
136168
range_stop_length(a, len::Integer) = range_step_stop_length(oftype(a-a, 1), a, len)

test/ranges.jl

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,20 @@
1818
# the next ones use ==, because it changes the eltype
1919
@test r == range(first(r), last(r), length(r) )
2020
@test r == range(start=first(r), stop=last(r), length=length(r))
21+
@test r === range( stop=last(r), length=length(r))
22+
23+
r = 1:5
24+
o = Base.OneTo(5)
25+
let start=first(r), step=step(r), stop=last(r), length=length(r)
26+
@test o === range(; stop )
27+
@test o === range(; length)
28+
@test r === range(; start, stop )
29+
@test r === range(; stop, length)
30+
# the next three lines uses ==, because it changes the eltype
31+
@test r == range(; start, stop, length)
32+
@test r == range(; start, step, length)
33+
@test r == range(; stop=Float64(stop))
34+
end
2135

2236
for T = (Int8, Rational{Int16}, UInt32, Float64, Char)
2337
@test typeof(range(start=T(5), length=3)) === typeof(range(stop=T(5), length=3))
@@ -1450,8 +1464,12 @@ end
14501464
@test_throws ArgumentError range(1)
14511465
@test_throws ArgumentError range(nothing)
14521466
@test_throws ArgumentError range(1, step=4)
1453-
@test_throws ArgumentError range(nothing, length=2)
1467+
@test_throws ArgumentError range(; step=1, length=6)
1468+
@test_throws ArgumentError range(; step=2, stop=7.5)
14541469
@test_throws ArgumentError range(1.0, step=0.25, stop=2.0, length=5)
1470+
@test_throws ArgumentError range(; stop=nothing)
1471+
@test_throws ArgumentError range(; length=nothing)
1472+
@test_throws TypeError range(; length=5.5)
14551473
end
14561474

14571475
@testset "issue #23300#issuecomment-371575548" begin

0 commit comments

Comments
 (0)