[swift-evolution] Feature proposal: Range operator with step

Ted F.A. van Gaalen tedvgiosdev at gmail.com
Thu Apr 7 14:31:09 CDT 2016


Hi All.

nearly no one has yet reacted on my mail, echoed here again,

which leaves by me the following questions pending:

-does what I define and describe completely cover all the required functionality
 for ranges for all numerical types?

-does it eliminate the need for using “Stride(...)”  at least for numerical scalars?

-combined with for .. in…  , is it an adequate replacement for the  classical for loop?

-can we eliminate  half open operators? Because imho that would simplify things greatly.
          -to which text of Dijkstra is this related?  


Objections? 
improvements? 
Things that I have missed? 
Feasibility? 
Implementable?

Thanks
TedvG





> On 06.04.2016, at 22:43, Ted F.A. van Gaalen <tedvgiosdev at gmail.com> wrote:
> 
> 
> 
> 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.
> 
> 
> 
> The basics:
> 
>     (v1…v2).by(v3)     // this still is readable. and can be optimized by the compiler (predictable sequence)    
> 
> Rules:
> 
>     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.
> 
> 
> valid examples:
>     (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
>                                                                        
>    
> 
>    invalid examples:
> 
>    (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
> like so:
> 
> v = v1 + v3 * i++;     v = v1 + v3 * i++;      v = v1 + v3 * i++;  v = 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) 
> TedvG
> 
>> on Wed Apr 06 2016, Erica Sadun <erica-AT-ericasadun.com <http://erica-at-ericasadun.com/>> wrote:
>> 
>>>    On Apr 6, 2016, at 12:16 PM, Dave Abrahams via swift-evolution
>>>    <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>>    (0..<199).striding(by: -2)
>>> 
>>>    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
>>> 
>>> -- E
>>> 
> 
>> -- 
>>> Dave
> 
> 
> 
> 
> 
> 
> 
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160407/a6bbdea3/attachment.html>


More information about the swift-evolution mailing list