Hi Erica, Dave
Based on what I’ve (not all) read under this topic:
I’d suggest a more complete approach:
Ranges should support: (as yet not implemented)
- All numerical data types (Double, Float, Int, Money***, Decimal*** )
- An arbitrary increment or decrement value.
- Working in the complete - + numerical range
- Allow traversing in both - + directions.
(v1…v2).by(v3) // this still is readable. and can be optimized by the compiler (predictable sequence)
v1, v2, v3 are any numerical type scalar type
v1, v2, v3 must have the same numerical type.
v1 > v2: is allowed and correctly evaluated. e.g. (8.0…-3.14159).by(-0.0001)
The ..< half open operator is no longer allowed. write e.g. 0...ar.count - 1
"by(…)” is obligatory with floating point range.
the default “by(…)” value of 1 makes sense only with integer ranges.
(5…9) // 5 6 7 8 9 Integer range without “by” defaults to 1 as increment value.
(1...10).by(2) // 1 3 5 7 9.
(2...10).by(2) // 2 4 6 8 10.
(4…-4).by(2) // 4 2 0 -2 -4 . // runs backwards
(30..-10).by(-2) // 30 28 26 24 22 ….. -10.
(10...0).by(-3) // 10 7 4 1.
(12…-10) // is valid, but returns empty because default increment value = 1
(12.0…-12.0).by(-1.5) // 12.0 10.5 9.0…. // of course with float imprecision
(23.0..<60.5).by(0.5) // half open ranges are no longer allowed **
(23.0…60.5) // “ by" is obligatory with floats.
(14...8).by(0.5) // v1 v2 and v3 don’t have the same numerical type
Half open ranges make no real sense (are not really useful) with floating point values.
and no sense at all with e.g (12..<-1) afaics
At least for float iterations the increment value should not each time be accumulated like
v1 += v3; v1 += v3; v1 += v3; …. // causes float number drift.
but be freshly multiplied with each iteration, e.g. by using an internal iteration counter
v1 = v3 * i++; v1 = v3 * i++; v1 = v3 * i++;….
for reasons of precision.
If one has worked with floating point data more often
awareness of its precision limitations become a second nature conscience.
E.g. it is perfectly acceptable and known (also in classical for-loops) that
(0.0…1.0).by(0.1) is not guaranteed to reach the humanly expected value of 1.0.
This is normal. Due to the nature of what mostly is done in the
floating point numbers domain, this does not often cause a problem
(e.g like working with a slide ruler)
if it is important to reach the “expected end” then one could
-add an epsilon value like so (v1…v2 + 0.1)
-generate the desired float sequence within an integer loop.
The above “range” (imho) improvement makes the
stride.. function/keyword completely unnecessary.
Due to its ability to process reversed ranges as is,
the .reverse() is optional (no longer necessary in most cases,
allowing the compiler to optimize without having to process
it like a collection.
Now that we have a fully functional range, which can do all things desired, one can
then of course, pass this range without any change to a collection based for … e.g.
for v in (v1…v2).by(v3) // optionally add other collection operators/filters/sorts here
(or in any other construct you might see fit)
This seems to be a reasonable alternative for
- the classical for ;; loop
-the collection-free for-loop
for v from v1 to v2 by v3
As you know, the latter is what I have been suggesting,
but seemingly does not find much support,
(because I received very little reactions)
making it doubtful if I will ever make a proposal for this for loop.
Anyone out there should I stil do that?
When one does not further extend the range
with filters like sort etc. the compiler can still optimize
a collection-in-between out of the way.
(Thank you Taras, für das Mitdenken. :o)
** note that a half open range would in most cases be unnecessary
if collection indexes started with 1 instead of 0, e.g. someArray[1…10]
(but it’s too late to change that.)
“the color of the first apple?” vs
“the color of the zeroth (0) ??? apple?” ? Silly isn’t?
*** possible future numerical “native” types
It could be that (at least) partly something similar has already been suggested.
but so much is here of this topic that i can’t see the wood for the trees, so to speak.
Your (all) opinions are appreciated.
kind regards, mit freundlichen Grüssen, Met vriendelijke groeten,
Sigh, why do we Dutch always have to speak the languages of the bigger countries :o)
are even or odd.
(0..<199).striding(by: -2): 0..<199 == 0...198 Even
(1..<199).striding(by: -2): 1..<199 == 1...198 Even
I understand the logic that got you there, but I find it incredibly
counter-intuitive that striding by 2s over a range with odd endpoints
should produce even numbers... I can't imagine any way I'd be convinced
that was a good idea.
(0..<198).striding(by: -2): 1..<198 == 0...197 Odd
(1..<198).striding(by: -2): 1..<198 == 1...197 Odd