A brave decision from the authors though, I think they would have got less flak matching the more popular 0-index languages.
Possibly, though those of us already in the space would have found it a (slightly) less pleasant language then.
I mean, computing mean - split range, get result per split and combine it back, and so on and so forth
I've always found 0-indexing mildly unpleasant too, even though C was the language I learnt programming with, and felt like I found home when I came across 1-indexed languages.
But I already know from real life that if there's maintanence in blocks 5 to 15, that's eleven blocks under maintanence. With half-open ranges, it once again introduces confusion and makes things unintuitive.
We can each find countless examples where each style comes out better, for eg `1:N` most often expresses the intent better than `range(N+1)`. I find people who prefer half-open ranges to be weird and incomprehensible, you probably find my preferences the same, I just don't like the categorical statement often made in this regard that one is inherently and universally superior to the other.
In Python, C/C++ and its descendant
[0...N)=[0...N/2)+[N/2...N)
Isn't that just n-1:-1:0 in Julia?
Was this sarcasm?
It's like the whitespace in Python debate that everyone gave up because the language got so popular that people stopped caring.
I thought the same thing about Python's indenting originally (and still do). But the ecosystem was enough to overcome it for me eventually.
You cannot do easily [0...N) = [0...N/2) + [N/2...N)
But really, these discussions are funny to me - each side pretending their convention is how God intended indexing to be done. You see it's naturally composable because N/2 shows up twice, which is really the perfect amount of times to show up, and as you recall I just defined composable in that way (not to mention it matches the fact that N/2 occurs twice in [0, N)!)
In Python (C, C++ with whole STL) you could split in the middle, or at any M
[0...N)=[0...M)+[M...N)
You could split it k times at any boundaries, still
[0...N)=[0...M1)+...+[Mk...N)
Another important thing is that number of elements to process is exactly the difference between last and first index of the range
And in Julia, it’s
length(a:b)
which also works with non-unit step sizes like length(a:x:b)
The intent of these expressions seems clearer than the intent of `b-a` and `ceiling((b-a)/x)` with your proposed approach in a zero-indexed language.I'm not quite sure that this is the case enough to say "typically". In terms of undergraduate exposure to math, I think more people have taken Calculus (or Analysis) than Linear Algebra, and I think Calculus textbooks tend to index from 0 while Linear Algebra textbooks tend to index from 1.
Assuming that arrays start at 1 is a source of occasional bugs in public packages. The existence of OffsetArrays means that arrays can start at any index (so for people who get nauseated by 1-based arrays, you can change it).
Instead, write "for i in eachindex(arr)".
In fact, Julia’s array syntax means you can loop over and manipulate arrays without using indexes much of the time, so don’t even need to know how they’re based.
Most modern languages have a «foreach» operator or its functional equivalent as a collection item generator. «foreach elem in my_collection {}» also has a clearly defined semantics: «process everything». The code is cleaner, concise and a bit shorter and reduces the cognitive overload. And since many languages now support lambdas, the code can quickly and error free be converted into a staged data processing pipeline without the use of temporary variables that serve no purpose, e.g. «foreach elem in my_collection.filter (_ -> _.my_selection_criteria ("42"); ) { do_something (elem); }». Whether the collection is indexed from 0 or from 1 becomes irrelevant.