-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
range(start, stop, length) #38750
Comments
xref #38041 (which is an open pull request) |
Related but orthogonal: the proposed three-arg version |
xref #37875 which is an open documentation only pull request |
Since nobody seems to think this is an extremely bad idea, I'll make a PR once #38041 is in |
What troubles me about this is the order of the arguments is not clear. I suggest a new name for this function that also communicates the order of the arguments. Keeping the current argument names I would prefer Part of the reason for the length is that the arguments are hard to unambiguously abbreviate. start -> begin This refers to existing indexing terms: julia> a = 1:0.2:5
1.0:0.2:5.0
julia> a[begin]
1.0
julia> a[end]
5.0
julia> length(a)
21
julia> step(a)
0.2 We could then have a group of range functions that use the first letters of
|
In this case, I'd personally use the constructor, i.e., I mean, it's totally fine to write some ad-hoc helpers for this, but I don't think they should live in Base. |
That does not help this PR where the request is for My position is that I would prefer |
One could just do one of the following in lieu of this PR.
#38041 implements
Lines 505 to 515 in 8c327e9
Overall, I find the original proposal confusing. 😕 |
Let's not overestimate the utility here of all different possible variants. Range is overwhelmingly used as
Of the remaining usages, most are kind of artificial:
. So clearly range is mostly used to create equispaced grids. The reason is that other uses already have the
Do you really use I like the idea of replacing start by begin and stop by end, but both begin and end are keywords. |
maybe we can get |
One downside: python has |
I agree that it's weird to require one keyword argument for a function like this, but Python's Triage notes that |
You have to give stop as a keyword:
|
My recommendation is consider #38041 which creates a |
@mkitti the point of this is to make things shorter: there's no real point in having a @triage Thanks for discussing this! Oof I did not know about python's |
Remember that we already have |
For those who are confused about order, there would still be the keywords, right? |
The implementation for the request here can be currently done in a single line of code which eventually leads to the use of Base.range(start, stop, length) = Base._range(start, nothing, stop, length)
Base.range(start, stop, length) = Base.range_start_stop_length(start, stop, length) @DNF2, If you want a drop-in replacement for MATLAB's linspace couldn't you just use julia> LinRange(0, 20, 61)
61-element LinRange{Float64}:
0.0,0.333333,0.666667,1.0,1.33333,1.66667,2.0,2.33333,…,17.6667,18.0,18.3333,18.6667,19.0,19.3333,19.6667,20.0
julia> len = typemax(Int)
9223372036854775807
julia> @benchmark LinRange(0, 10, $len)
BenchmarkTools.Trial:
memory estimate: 0 bytes
allocs estimate: 0
--------------
minimum time: 0.001 ns (0.00% GC)
median time: 0.001 ns (0.00% GC)
mean time: 0.027 ns (0.00% GC)
maximum time: 0.101 ns (0.00% GC)
--------------
samples: 10000
evals/sample: 1000 If you really want julia> Base._linspace(0. , 20. , 21)
0.0:1.0:20.0 To summarize, the function proposed here is an alias for a function that currently lives in Base. The main thing in contention here is if we should call this function by a different name that is exported.
|
This is detailed in the docs, LinRange is less careful about floating point errors than Generally speaking, in julia for this kind of work you don't usually call a constructor directly, and therefore using I don't actually particularly care which of |
I don't really see calling the constructor as an issue, but I can see the having to the push the shift key could be annoying. Would calling it julia> linspace(start, stop, length) = Base._range(start, nothing, stop, length)
linspace (generic function with 1 method)
julia> linrange(start, stop, length) = Base._range(start, nothing, stop, length)
linrange (generic function with 1 method) Would you want a one or two argument version or having a length argument of |
Maybe defining
|
I think the name |
Numpy also has There https://github.com/numpy/numpy/blob/v1.19.0/numpy/core/function_base.py#L24 Likewise, A potential issue for us is that in each of these cases |
@JeffBezanson commented on this before as noted in the source code: Also In [16]: [i for i in range(1,5)]
Out[16]: [1, 2, 3, 4]
In [17]: [i for i in range(5)]
Out[17]: [0, 1, 2, 3, 4] As much as I like |
From that you might expect a
I wrote up documentation on how to create a Lines 158 to 167 in 20b84f4
|
@MasonProtter just had a great idea in the Zulip chat. Why don't we give julia> Base.range(unit_range::UnitRange, length=nothing) = Base._range(unit_range.start, nothing, unit_range.stop, length)
julia> Base.range(pair::Pair, length=nothing) = Base._range(pair.first, nothing, pair.second, length)
julia> range(1:2)
1:2
julia> range(1:2, 5)
1.0:0.25:2.0
julia> range(3 => 5.6, 261)
3.0:0.01:5.6
We could even switch the order around and have both forms. julia> Base.range(length, unit_range::UnitRange) = Base._range(unit_range.start, nothing, unit_range.stop, length)
julia> Base.range(length, pair::Pair) = Base._range(pair.first, nothing, pair.second, length)
julia> range(5, 1:2)
1.0:0.25:2.0
julia> range(1:2, 5)
1.0:0.25:2.0
julia> range(100, 0 => 2π)
0.0:0.06346651825433926:6.283185307179586 |
Noting that Colors.jl has a three-position |
As discussed in #39071, using |
It would be good to revisit the conversations in #25896 in #28708 to see where many of these matters were previously discussed including the existence of |
Triage is in favor of this. |
Triage is inclined to do this and also supports |
Does this mean no two argument then? No two positional argument version is currently defined. Per above, I would be interested in |
I'm kinda disappointed we're not going with It's impossible to make the 2-arg version be anything else than |
Adding I'm torn on which set of positional signatures makes more sense. One option is the "stop-oriented" design:
The other option is the "length-oriented" design:
Note that these only different in behavior of the middle two-argument signature. Are there any other positional schemes that have been proposed that I'm missing? The other one would be for |
Yeah, I just liked the consistency The most consistent version would be to follow the principles "three arguments, or two non-step, in which case step is 1" plus the order (start, stop, length) to the end. This would mean forbidding one positional argument (since it doesn't match the rule) and have |
I see a Julian |
For the
I would deprecate 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 |
IMO |
I would lean towards deprecation of If you really want keywords galore for very specific syntax you still have
|
I think that given that we already allow |
For 1.0 we had a push to introduce keyword arguments in the public API (see #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 |
Is it The difference is Do we need to define two forms of a single argument 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 |
For three argument If |
I think the answers to most of my questions on Lines 131 to 146 in 65898ed
|
I'm leaving a note in this design issue that my last effort towards The main motivation for However,
As I do not see a path forward on |
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.The text was updated successfully, but these errors were encountered: