diff --git a/NEWS.md b/NEWS.md index d994c3d2f17fc..73e906727807b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -40,6 +40,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]). * `islowercase` and `isuppercase` are now compliant with the Unicode lower/uppercase categories ([#38574]). * `iseven` and `isodd` functions now support non-`Integer` numeric types ([#38976]). diff --git a/base/range.jl b/base/range.jl index dacf60212b19c..7278d8dc61e9b 100644 --- a/base/range.jl +++ b/base/range.jl @@ -47,6 +47,7 @@ function _colon(start::T, step, stop::T) where T end """ + range(start, stop, length) range(start, stop; length, step) range(start; length, stop, step) range(;start, length, stop, step) @@ -96,34 +97,19 @@ julia> range(1, 3.5, step=2) Special care is taken to ensure intermediate values are computed rationally. To avoid this induced overhead, see the [`LinRange`](@ref) constructor. -Both `start` and `stop` may be specified as either a positional or keyword arguments. -If both are specified as positional arguments, one of `step` or `length` must also be provided. - !!! compat "Julia 1.1" `stop` as a positional argument requires at least Julia 1.1. !!! compat "Julia 1.7" - `start` as a keyword argument requires at least Julia 1.7. + The versions without keyword arguments and `start` as a keyword argument + require at least Julia 1.7. """ function range end range(start; stop=nothing, length::Union{Integer,Nothing}=nothing, step=nothing) = _range(start, step, stop, length) - -function range(start, stop; length::Union{Integer,Nothing}=nothing, step=nothing) - # For code clarity, the user must pass step or length - # See https://github.com/JuliaLang/julia/pull/28708#issuecomment-420034562 - if step === length === nothing - msg = """ - Neither `step` nor `length` was provided. To fix this do one of the following: - * Pass one of them - * Use `$(start):$(stop)` - * Use `range($start, stop=$stop)` - """ - throw(ArgumentError(msg)) - end - _range(start, step, stop, length) -end +range(start, stop; length::Union{Integer,Nothing}=nothing, step=nothing) = _range(start, step, stop, length) +range(start, stop, length::Integer) = _range(start, nothing, stop, length) range(;start=nothing, stop=nothing, length::Union{Integer, Nothing}=nothing, step=nothing) = _range(start, step, stop, length) diff --git a/test/ranges.jl b/test/ranges.jl index 899cba13f47b9..937aabe471561 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -1,26 +1,26 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license @testset "range construction" begin - @testset "range(;kw...)" begin - @test_throws ArgumentError range(start=1, step=1, stop=2, length=10) - @test_throws ArgumentError range(start=1, step=1, stop=10, length=11) - - r = 3.0:2:11 - @test r == range(start=first(r), step=step(r), stop=last(r) ) - @test r == range(start=first(r), step=step(r), length=length(r)) - @test r == range(start=first(r), stop=last(r), length=length(r)) - @test r == range( step=step(r), stop=last(r), length=length(r)) - - r = 4:9 - @test r === range(start=first(r), stop=last(r) ) - @test r === range(start=first(r), length=length(r)) - # the next one uses ==, because it changes the eltype - @test r == range(start=first(r), stop=last(r), length=length(r)) - @test r === range( stop=last(r), length=length(r)) - - for T = (Int8, Rational{Int16}, UInt32, Float64, Char) - @test typeof(range(start=T(5), length=3)) === typeof(range(stop=T(5), length=3)) - end + @test_throws ArgumentError range(start=1, step=1, stop=2, length=10) + @test_throws ArgumentError range(start=1, step=1, stop=10, length=11) + + r = 3.0:2:11 + @test r == range(start=first(r), step=step(r), stop=last(r) ) + @test r == range(start=first(r), step=step(r), length=length(r)) + @test r == range(start=first(r), stop=last(r), length=length(r)) + @test r == range( step=step(r), stop=last(r), length=length(r)) + + r = 4:9 + @test r === range(start=first(r), stop=last(r) ) + @test r === range(start=first(r), length=length(r)) + @test r === range( stop=last(r), length=length(r)) + @test r === range(first(r), last(r) ) + # 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)) + + for T = (Int8, Rational{Int16}, UInt32, Float64, Char) + @test typeof(range(start=T(5), length=3)) === typeof(range(stop=T(5), length=3)) end end @@ -1630,8 +1630,6 @@ end end end end - # require a keyword arg - @test_throws ArgumentError range(1, 100) end @testset "Reverse empty ranges" begin