Closed antoine-levitt closed 3 years ago
range(start, stop)
is just start:stop
like range(start, step, stop)
is just start:step:stop
. Adding either range(start, stop)
and range(start, step, stop)
just adds redundancy.
For the length
oriented design, we can just document this as:
`length` is always the last argument when only positional arguments are used.
I would deprecate range(start, stop; length)
by just removing the documentation for it and leaving range(start, stop; step)
. I'm not sure why you would use range(start, stop; length)
when you have range(start, stop, length)
. It could be left as a compatibility note.
The combined documentation would then be:
range( length )
range( start, length )
range( start, stop, length )
range( start, stop; step )
range( start; stop, step, length )
range(; start, stop, step, length )
The code part of the PR is then three lines:
# One positional argument
range(length::Integer) = Base.OneTo(length) # Integers only!
# range(stop) = Base.OneTo(stop) # Equivalent
# range(start, stop) = range_start_stop(start, stop) # Redundant with `start:stop`
range(start, length) = range_start_length(start, length) # Julia is not Python
# Three positional argument
range(start, stop, length) = range_start_stop_length(start, stop, length)
We might almost as well just fold this into #38041 since that is also approved and the effective code is just two or three lines aliasing into non-exported functions that were created in #38041 .
I considered range( [ start, [ stop, ] ] length )
. If compactness were key, it might work. Otherwise, it is challenging to read.
IMO range(start, length)
is a non-starter due to range(start, stop; ...)
. I think the "length-oriented" design is overly confusing due to that existing signature.
IMO
range(start, length)
is a non-starter due torange(start, stop; ...)
. I think the "length-oriented" design is overly confusing due to that existing signature.
I would lean towards deprecation of range(start, stop; ...)
in Julia 2.0 and de-emphasizing its documentation now.
range(start, stop; length)
would be covered by range(start, stop, length)
range(start, stop; step)
is covered by start:step:stop
range(start, stop; step, length)
, with both keywords specified, causes an error
If you really want keywords galore for very specific syntax you still have
range(start; stop, step, length)
for a highly backwards compatible syntax and now
range(; start, stop, step, length)
range(start, stop; ...)
can still work for compatibility reasons only, but I'm failing to see why that might hinder us in the long term. It has little use after we add this and the all keyword version.
I think that given that we already allow range(start, stop; length)
and range(start, stop; step)
we're pretty much forced to go with the "stop-oriented" design. I don't really think that either design is strictly better or worse, so I'm fairly happy to have a decision forced upon us.
For 1.0 we had a push to introduce keyword arguments in the public API (see https://github.com/JuliaLang/julia/issues/25188 for example) partly to avoid ambiguous cases just like this IIRC. Are people really using this function frequently enough such that having to type length=
is a problem?
Note, too, that it becomes more useful if it returns a
Base.OneTo
— which is commonly used in high-performance axis munging.
Is it range(stop)
or range(length)
?
The difference is length
has long been an Integer
and Base.OneTo
only accepts an Integer
. Meanwhile, stop
can be anything, or at least any Number
.
Do we need to define two forms of a single argument range
?
range(stop) = range_start_stop( oneunit(stop), stop ) # Equivalent to `1:stop`
range(length::Integer) = Base.OneTo( length )
Or should we restrict it to only Integer
?
For three argument range(start, stop, length)
can length
or any of the arguments be nothing
?
If length == nothing
, then this just becomes equivalent to range(start, stop)
.
stop
could be nothing if length
is not nothing
. This should be equivalent to range(start; length)
start
could be nothing if either stop
or length
is defined. If only one is defined, then start
defaults to 1
.
I think the answers to most of my questions on nothing
can be deferred to the Base._range
4-argument block in #38041
One option is the "stop-oriented" design:
range(stop)
withstart = step = 1
I'm leaving a note in this design issue that my last effort towards range(stop)
in the stop-oriented design above is in #39241 which implements the keyword form range(; stop)
which is a necessary precedent to range(stop)
.
The main motivation for range(stop)
is to provide the Python user coming to Julia some familiarity as expressed in this Discourse comment.
However, range(stop)
, the positional form, has some outstanding questions and concerns:
stop
be any valid value for which oneunit(stop):stop
works?stop
be an Integer
when given as a single argument? In Python, range(stop)
only accepts integers.range(stop; stop, length, step)
?start
when given with a keyword, but stop
without a keyword?axes
and eachindex
can produce an AbstractUnitRange
, Base.OneTo
, but range
cannot create this exactly, in terms of ===
?As I do not see a path forward on range(stop)
in the next few releases, I'm moving on. I'm sorry to disappoint Stefan's sympathies. Thank you for the discussion.
This issue is to propose defining
range(start, stop, length) = range(start, stop; length=length)
. I searched the issues and PR, expecting pages of heated debate, but I couldn't find any, so here goes.Pros:
grep -r ' range('
in my .julia/packages returns lots of hits, almost all of which arerange(start, stop; length=length)
. Doing the same in my research codes has a lot more, all of them of this form. Most of my usage is either discretization of a differential equation or plotting of a function.length
is very annoying. I think this is the reason why some people useLinRange
, which increases fragmentation and makes people use LinRange when they probably shouldn't (it's low-level compared torange
)step
already has its own nice syntax (a:b:c
),length
is missing oneCons:
range(a, b, c)
anda:b:c
do the same thing. I don't think this is a serious problem since thea:b:c
syntax is clearly special, and not analogous to function calls (since the additional argument comes in the middle)range(a, b, c)
andLinRange(a, b, c)
would not be similar syntax for different thingsrange(0, 1, length=100)
does;range(0, 1, 100)
is more implicit and can plausibly cause confusion. I think it's usually clear from the context. In most of examples taken from my usage, thelength
keyword was calledN
or something explicit like that.