-
-
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
Why is length
defined on numbers?
#11769
Comments
They are in Julia: julia> for a in 1
@show a
end
a = 1 |
AHH, BUT WHYYY? |
It's considered practical by some people. The question is rather whether this has drawbacks or not. Else there's no reason to remove that. FWIW, please use the mailing list for questions in the future, and keep GitHub for bug reports. |
FWIW, I consider this a mistake, it has bitten me way too many times. |
I also find it a bad idea, but github may not be the place to revive the debate |
This just reeks of MATLAB to me. |
@samuela the supported iteration / indexing interface is to basically treat scalars as zero dimensional arrays. |
It is way too easy to miss a colon in a for loop and only do one iteration - I remember vividly how I spent a week debugging why my locality sensitive hash wasn't local - I had |
Yeah, I'm not a great fan of this either. :-/ |
Yes I really think we should experiment with removing iteration of numbers. I think the array indexing redesign might make this possible. |
This is the bug I most often hit these days. |
Here was my last 15-minute attempt at making numbers non-iterable: #10331 (comment) |
Just to balance the opinions here, I'll mention I use this feature a lot and find it quite handy. |
@carlobaldassi what does a typical use look like? |
@joehuchette : for example: I have functions which explore ranges of parameters for collecting data. Most of the time I need to change one parameter or two, and keep the rest at some value. So I just have function signatures like |
Why not |
@carlobaldassi What does that do to the code generated? Doesn't that cause problems of type instability, if the argument could either be a scalar or a range? Instead of |
@samuela; Here's a line I just entered in the REPL minutes ago:
I suppose you can see how it might become annoying to add Anyway, as I said, it's probably not the best example, just one possible way to show how my life is a little easier because numbers are iterable. @ScottPJones : this is not a hot loop, it's just the interface. Each iteration takes at least tens of seconds, at worst hours (and I can assure you I've been optimizing that quite aggressively). As I said, it's basically an API for me interacting with the REPL, and you may see that I already type plenty. |
OK, thanks for the explanation... with all this math stuff, I feel it's way over my head sometimes! 😀 |
The biggest advantage of our current system is that it allows you to use a single algorithm for vectors or scalars without having to allocate an array to pass a scalar. There are many instances where simply wrapping that scalar as julia> function sumelts(A)
s = 0.0
for a in A
s += a
end
s
end
sumelts (generic function with 1 method)
julia> function timeit1(n)
S = 0.0
for i = 1:n
S += sumelts(i)
end
S
end
timeit1 (generic function with 1 method)
julia> function timeit2(n)
S = 0.0
for i = 1:n
S += sumelts([i])
end
S
end
timeit2 (generic function with 1 method)
# Warmup suppressed
julia> @time timeit1(10^6)
12.690 milliseconds (6 allocations: 176 bytes)
5.000005e11
julia> @time timeit2(10^6)
94.928 milliseconds (1999 k allocations: 93742 KB, 21.42% gc time)
5.000005e11 While on balance I favor this feature, at the same time I am aware that it can cause problems. If folks decide it's simply too bug-prone, I will learn to live with its removal and write two implementations of algorithms where I am exploiting this feature. |
I know it's not idea, but what about an iterator that for scalars makes them iterable and for everything else just passes through. That way in the limited cases where this is useful, it is still possible (albeit a little ugly), while avoiding the trap in the common case. |
Like this? julia> immutable Container{T}
val::T
end
julia> Base.start(c::Container) = 1
start (generic function with 47 methods)
julia> Base.next(c::Container, index::Int) = (c.val, 2)
next (generic function with 60 methods)
julia> Base.done(c::Container, index::Int) = index != 1
done (generic function with 49 methods)
julia> function timeit3(n)
S = 0.0
for i = 1:n
S += sumelts(Container(i))
end
S
end
timeit3 (generic function with 1 method)
julia> @time timeit3(10^6)
75.680 milliseconds (3000 k allocations: 46875 KB, 13.54% gc time)
5.000005e11 Sniff. |
What about a range? Is that going to cause numeric problems? function timeit4(n)
S = 0.0
for i in 1:n
S += sumelts(i:i)
end
S
end |
It is possible that we have a codegen regression within the past week, there have been a number of changes to codegen, but on my week old version of julia the generated code is identical. |
Much better---amazing what a difference a small tweak makes. @johnmyleswhite, your version is also faster than what I posted, though worse than @Keno's if you use Assuming this solution generalizes to less-trivial functions, I have no substantive objections to changing this. |
This is effectively what I did to simplify |
I tried @timholy 's code and I don't see any allocation. Maybe a slow definition was polluting the method cache somehow? Another good option is to use a 1-tuple ( |
@JeffBezanson well, there's the concern on not wanting to type those three extra characters at the REPL every time. |
Libraries could also use
instead of a new type. |
FWIW, one reason not to treat scalars as collections is the inconsistency with indexing dropping or not (trailing) dimensions. For example, if |
Numbers are actually 0-dimensional, so they have a single element without being vectors. |
I also lost a couple of hours due to for i in length(x) It'd be great to catch this in some way (which I now do via syntax highlighting, at least). |
While I still support making scalars non-iterable, the rise of the |
+1 for making scalars non-iterable. I think this would help solve several other consistency issues. For example |
If something is messed up with my code, it feels like it is 90% of the times because I have written |
Maybe make scalars non-iterable first thing in 0.5? If |
@ScottPJones +1 |
I discovered from a typo today that the
length
method is defined on numbers:It's defined here: https://github.com/JuliaLang/julia/blob/master/base/number.jl#L12. Why is
length
defined on numbers? This seems counterintuitive. Numbers aren't iterable in any way after all.The text was updated successfully, but these errors were encountered: