A (better) Swift Equivalent For The Classical For-Loop With Numeric Scalars


(Ted van Gaalen) #1

I still would like to see this new for-loop statement be implemented in the next Swift version

Examples:
     for v from 0.5 to 30.0 by 0.3 // floating point types
     for v from 0 to 100 by 5 // Integer
     for v from 12.0 to -10.0 by -2 // Floating points backward

the “by …” clause is optional for Ints only

As previously written, a tolerance factor could also be implemented as optional,
allowing to “end on a humanly accepted boundary” so like in this example
the highest loop value would be 10.0 (+/- ca. 0.000000001) , not 9.9 :
  
for v from 0.0 to 10.0 by 0.1 tolerance 0.001

// the “tolerance ..” clause is optional and allowed for floating point vars only

Again I need to emphasize very strongly that this for-loop really
has absolutely
     nothing, nada, zilch, niente, nichts, niets, niks, rien, zero, nenio,
to do with the:

for i in stride(….

or any other for in… variant working with collections.

However inexplicably, in the previous discussions, a lot of people ***
tried desperately to replace this simple but precious gem,
a miracle of astonishing beauty: (sorry, got carried away a bit :o)
  
    for v from v1 to v2 by vstep

with the collection based

for in ….

The for in… is wonderful for collection based iterations, I use it
all the time like
    for thing in things // etc.

for d in 10.0.stride(to: 5.0, by: -0.1)
{
    print(d)
}

but, once again -
provided you don’t want to do other operations
on the generated collection before iterating -
a collection is used here totally unnecessary,
which puts a burden on performance because the contents
of a collection are unpredictable
It is also tedious to write and (as a matter of my personal taste) downright ugly.

Imho this looks a whole lot better and can also be very efficiently compiled:

for d from 10.0 to 5.0 by -0.1 tolerance 0.01
{
    print(d)
}

  **************************** !!! **************************************
  Important is to see that this “for…” is in fact
  a convenience solution for “while” and “repeat” constructs:
  and thus a totally different beast compared to the "for in…” !

···

*********************************************************************
var d = 10.0
var v = 0.0
let step = 0.1

while d > 5.0
{
    print(d)
    d -= step
}

The above is a bare minimum “while” equivalent
for the above for-loop, but still tedious to write!

What more can I write to convince?

*** Please tell me if I am wrong, but:
I am inclined to think that Functional Programming Minded
Colleagues are trying to push persistently their
(mathematically correct?) way of thinking upon Swift,
thereby ignoring that Swift is and should remain a
general purpose programming language.

TedvG
www.ravelnotes.com

@Erica,

Erica, as I seem to remember, You wrote somewhere
that Stride is broken, but the "10.0.stride…” example
above works perfectly well in Swift 2.2. playground.

So, what do you regard as wrong with it?
(apart from in some cases needing to specify an
epsilon(tolerance) value? )


(Taras Zakharko) #2

Again I need to emphasize very strongly that this for-loop really
has absolutely
     nothing, nada, zilch, niente, nichts, niets, niks, rien, zero, nenio,
to do with the:

for i in stride(….

or any other for in… variant working with collections.

Of course it does. Collection-based for loop can express exactly the same semantics, so why do you need a new construct when you already have a perfectly good one to do the job?

but, once again -
provided you don’t want to do other operations
on the generated collection before iterating -
a collection is used here totally unnecessary,
which puts a burden on performance because the contents
of a collection are unpredictable

I find it quite irritating that you keep repeating these untrue facts. Again: both for loops compile to exactly the same code.

It is also tedious to write and (as a matter of my personal taste) downright ugly.

Right, because

for d in stride(from:10, to: 5, by: 0-.1, tolerance: 0.01)

is that much more tedious to write than what you propose

Best,

Taras

···

On 30 Mar 2016, at 22:05, Ted F.A. van Gaalen via swift-evolution <swift-evolution@swift.org> wrote:


(Ted van Gaalen) #3

Grüezi wohl Taras

you wrote:

I find it quite irritating that you keep repeating these untrue facts. Again: both for loops compile to exactly the same code.

Alas, I don’t understand you irritation,
but it is your irritation, not mine.

Please note again, that “for ... in …” always has
some sort of collection type as its argument..
At run time, the content of a collection
is in most cases unpredictable.
Ergo: this implies that in these cases,
the compiler cannot optimize the collection
part of the “for … in …” statement out of the way.
In an attempt to overcome this restriction,
it would need to analyze all entities that have
influenced the content of the collection,
which is virtually impossible.
     
I do not understand your aversion against
the for loop I brought forward, as it does not
conflict at all with the “for ... in …” construct
and probably also does not stand in the way
of possible future extensions that could be
added to the "for in..” construct.

E.g. For similar reasons one could be irritated by
the brave attempts of some of us to supply
most peculiar variants of “Strides", seemingly,
at least as seen from my limited perspective,
to compensate the loss of the classical for-loop’s
facilities...
In spite of all this being very fascinating and
creative, to me, this effort is comparable with
trying to climb the Eiffel tower, equipped
with boxing gloves and diving fins.
it could irritate me.. However it does not,
for the mere reason that I do not fully
understand their motives and logical grounds...
Nevertheless, they might -or might not-
have good reasons to do so, as we no
doubt will find out sooner or later...
In any case, this does affect the collection-based
“for … in …” only, and has no impact on the
“for v from v1 to v2 by vstep”
that I am proposing.

Collection-based for loop can express exactly the same semantics, so why do you need a new construct when you already have a perfectly good one to do the job?

For the simple reason that there are no collections involved:
I have very clearly described and motivated it.
Please read it again, thank you.

By the way, it is not a new construct as it has been
existing for decades.

I took the liberty to read about you on the internet. Interesting.

I’ve read that you have a degree in linguistics,
which makes me assume that of all people,
you’d understand that in most languages
there are many different ways to express something,
and that the way to express or say something
is mostly determined by contextual aspects...
So in the light of this very specific knowledge
that you have, I fail to understand what your
objections are against the presence of
two slightly different for-loop variants
that can co-exist easily and are effective,
each in its own different context?

Last but not least, you might find this interesting:
(although I am almost sure you have read it before)

http://blog.oxforddictionaries.com/2014/09/george-orwell-newspeak/

and then most particularly in this text:

“Newspeak goals and real-world ramifications”

I cannot completely clear myself from the association
of this with the removal of certain Swift language
elements..

Met vriendelijke groeten.
TedvG

···

On 31.03.2016, at 10:11, Taras Zakharko <taras.zakharko@googlemail.com> wrote:

On 30 Mar 2016, at 22:05, Ted F.A. van Gaalen via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Again I need to emphasize very strongly that this for-loop really
has absolutely
     nothing, nada, zilch, niente, nichts, niets, niks, rien, zero, nenio,
to do with the:

for i in stride(….

or any other for in… variant working with collections.

Of course it does. Collection-based for loop can express exactly the same semantics, so why do you need a new construct when you already have a perfectly good one to do the job?

but, once again -
provided you don’t want to do other operations
on the generated collection before iterating -
a collection is used here totally unnecessary,
which puts a burden on performance because the contents
of a collection are unpredictable

I find it quite irritating that you keep repeating these untrue facts. Again: both for loops compile to exactly the same code.

It is also tedious to write and (as a matter of my personal taste) downright ugly.

Right, because

for d in stride(from:10, to: 5, by: 0-.1, tolerance: 0.01)

is that much more tedious to write than what you propose

Best,

Taras


(Taras Zakharko) #4

Alas, I don’t understand you irritation,
but it is your irritation, not mine.

Well, its quite simple: we are having a discussion here. You are claiming that the collection-based iteration is inherently slower than a classical numerical loop. This is incorrect. I have even sent around some C code that uses different abstractions and shown that it compiles to the same machine code. Yet you are consistently ignoring this.

Please note again, that “for ... in …” always has
some sort of collection type as its argument..
At run time, the content of a collection
is in most cases unpredictable.

Again, incorrect. The simple collections that are relevant to this discussion are based on trivial iterators that can be statically dispatched and inlined by the compiler. They can potentially even be unrolled (although I doubt that Swift optimiser does this kind of optimisation currently). Again, the difference between

for(int i = x0; i<x1; i++)

and

for(int i = iterator->next(); !iterator->endReached, int i = iterator->next())

is just one level of indirection. If the value of iterator->next() is available at the compile time and the compiler can safely assume that the iterator has a unique reference, the code can be inlined, producing the same loop as above

E.g. For similar reasons one could be irritated by
the brave attempts of some of us to supply
most peculiar variants of “Strides", seemingly,
at least as seen from my limited perspective,
to compensate the loss of the classical for-loop’s
facilities…

I am not at all a fan of the stride() method because they are weird to read. However, a stride() global function will do the job just fine, as shown by the example of such languages as R and Python, which are used quite prominently in the numerical domain (there the functions are called seq() and range() )

For the simple reason that there are no collections involved:
I have very clearly described and motivated it.

Your description clearly involve numerical sequences. So they perfectly well fall into the domain of sequence-based iteration.

I took the liberty to read about you on the internet. Interesting.

Thank you, its very flattering :slight_smile:

I fail to understand what your
objections are against the presence of
two slightly different for-loop variants
that can co-exist easily and are effective,
each in its own different context?

In case I didn’t explain my reasoning clear enough, here is another attempt. Swift already has a very powerful, compact tool that offers a strict superset of the iteration semantics. I simply see no purpose into making the language more verbose and complicated for no particular gain. What you do is argue for having two different syntactic styles for accomplishing exactly the same thing, simply on the grounds of your personal dislike of one of them.

Best,

Taras

···

On 31 Mar 2016, at 14:12, Ted F.A. van Gaalen <tedvgiosdev@gmail.com> wrote:


(Ted van Gaalen) #5

Hi Taras

I’ve watched the WWDC15 video about Swift compiler optimization, read some more
in depth material about it. It is probably advanced in many aspects of optimization.
So, you might be correct to assume that the compiler can optimize

     for(int i = x0; i<x1; i++)

(also with floats)
and perhaps also for a collection based variant such as:

     for v in stride(from -8.4, to: 3.2, by 0.1)

In any case, I don’t know for sure. I am not a compiler specialist
Therefore I void our argument about whether or not the compiler
can do enough magic to get it right.

Still, there are no good alternatives for the many advanced possibilities
which traditional for loop offers.
E.g.
In the Apple TV app I am currently working on I had to refactor
my for ;; loops with reversing floats with step values to “while” loops!

So, to me the best option is still to bring the for ;; back
or to make a new Swift equivalent for it as described here again.

for d from 10.0 to 5.0 by -0.1 tolerance 0.01 //tolerance is optional
{
    print(d)
}

-=straight from the front line: =-
Because my music maker apps RavelNotes and RavelNotesBasic are still
for the most part Objective C sources, I only have to do this in the Swift
sources of my apps.
Now, I have to refactor (only) about 10 for ;; loops to for in.. loops
and have to convert about 10 ++ to += things.
Luckily, they are all for-loops with integers, so the refactoring
itself took less than hour, that was no problem.
However, now I have to thoroughly retest everything again,
costing me several days or so, before I can submit a
new release of my apps to the app store!!
I am still lucky not to work for a company and
having to convert a lot more source code.
I was considering converting more ObjC to Swift, put
put this on halt until Swift stabilizes.

Now, like me, many programmers have to do a
whole lot of nasty for-loop refactoring!

Therefore, excuses moi, but currently I can’t help
being in a state just somewhere between
annoyed and aggravated because I am unnecessarily
waisting lots of time due to some puritan obsessed
decisions, partially from some people with high
theoretical knowledge but very little practical experience,
or so it seems.
Don’t get me wrong:
Swift is great, e.g. i like the new protocol developments, and of course I understand
(and support) that one needs to be very thoughtful about components of the language.
But one should be pragmatic as well.

···

-==-

You also wrote:

In case I didn’t explain my reasoning clear enough, here is another attempt. Swift already has a very powerful, compact tool that offers a strict superset of the iteration semantics.

That is not (yet) the case, let alone a superset!

I simply see no purpose into making the language more verbose and complicated for no particular gain.

It doesn’t make the language more complicated, rather, the reverse is true.
If you want a less verbose language, learn APL, or J.
APL proves unintentionally the inverse relation between “verbose”and “complicated” :o)

What you do is argue for having two different syntactic styles for accomplishing exactly the same thing,
simply on the grounds of your personal dislike of one of them.

It is not at all personal dislike, it is many years of die-hard experience
with a multitude of programming languages and systems.
I don’t think in emotional terms about programming constructs but
solely about practical implications, usefulness, reliably and so on.

I assume this difference of opinion will remain...

     -----
Coincidentally, today John Heerema, described here on swift-evolution
exactly my point of view on these matters based on facts.
read his text please. Thank you.
     -----
I hope I am not too unfriendly here, Nothing personal.
If I am in Zürich again it would be nice to discuss this with a beer.
Although not so far from here, currently my finances prevent this.

Kind regards
Ted
www.ravelnotes.com

  == The problem is not what you add to a programming language
  == but what you remove!
  

On 31.03.2016, at 14:59, Taras Zakharko <taras.zakharko@uzh.ch> wrote:

On 31 Mar 2016, at 14:12, Ted F.A. van Gaalen <tedvgiosdev@gmail.com> wrote:

Alas, I don’t understand you irritation,
but it is your irritation, not mine.

Well, its quite simple: we are having a discussion here. You are claiming that the collection-based iteration is inherently slower than a classical numerical loop. This is incorrect. I have even sent around some C code that uses different abstractions and shown that it compiles to the same machine code. Yet you are consistently ignoring this.

Please note again, that “for ... in …” always has
some sort of collection type as its argument..
At run time, the content of a collection
is in most cases unpredictable.

Again, incorrect. The simple collections that are relevant to this discussion are based on trivial iterators that can be statically dispatched and inlined by the compiler. They can potentially even be unrolled (although I doubt that Swift optimiser does this kind of optimisation currently). Again, the difference between

for(int i = x0; i<x1; i++)

and

for(int i = iterator->next(); !iterator->endReached, int i = iterator->next())

is just one level of indirection. If the value of iterator->next() is available at the compile time and the compiler can safely assume that the iterator has a unique reference, the code can be inlined, producing the same loop as above

E.g. For similar reasons one could be irritated by
the brave attempts of some of us to supply
most peculiar variants of “Strides", seemingly,
at least as seen from my limited perspective,
to compensate the loss of the classical for-loop’s
facilities…

I am not at all a fan of the stride() method because they are weird to read. However, a stride() global function will do the job just fine, as shown by the example of such languages as R and Python, which are used quite prominently in the numerical domain (there the functions are called seq() and range() )

For the simple reason that there are no collections involved:
I have very clearly described and motivated it.

Your description clearly involve numerical sequences. So they perfectly well fall into the domain of sequence-based iteration.

I took the liberty to read about you on the internet. Interesting.

Thank you, its very flattering :slight_smile:

I fail to understand what your
objections are against the presence of
two slightly different for-loop variants
that can co-exist easily and are effective,
each in its own different context?

In case I didn’t explain my reasoning clear enough, here is another attempt. Swift already has a very powerful, compact tool that offers a strict superset of the iteration semantics. I simply see no purpose into making the language more verbose and complicated for no particular gain. What you do is argue for having two different syntactic styles for accomplishing exactly the same thing, simply on the grounds of your personal dislike of one of them.

Best,

Taras