hsutter / cppfront

A personal experimental C++ Syntax 2 -> Syntax 1 compiler

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[QUESTION] cpp2 for loops

dutkalex opened this issue · comments

Hi! My question is rather simple, but I could not find the answer in the documentation nor in other issues. What is the cpp2 equivalent for:

for ( int i = a; i < b; ++i ){
  // loop body
}

All the examples in the documentation seem to be range-based for loops, and the closest I could find (which is obviously not the right answer) is:

for std::views::iota{ a, b } do ( i ){
  // loop body
}

Thanks for the amazing work!
Best regards,
Alex

That's a good question I should cover somewhere. Here's the quick answer:

auto cpp1() {
    //  Prints: 0123456789
    for ( int i = 0; i < 10; ++i ){
        std::cout << i;
    }
    std::cout << "\n";
}

main: () = {
    cpp2();

    //  Prints: 0123456789
    (copy i := 0) while i < 10 next i++ {
        std::cout << i;
    }
    std::cout << "\n";

    // Same, just my personal whitespace style
    (copy i := 0)
    while i < 10
    next  i++ {
        std::cout << i;
    }
    std::cout << "\n";
}

Line by line (and why I like being able to write the parts on individual lines):

  • (copy i := 0): Any statement can have statement-local parameters, so this is just declaring i as an int that's local to the loop. Parameters by default are const (and for not-cheap-to-copy types bind to the original value), so because I want to modify it I use copy to explicitly declare this is my own mutable scratch variable. (I find that statement-local parameters initially take getting used to the first couple of times, then are easy to remember and use because they work with any statement including blocks.)
  • while i < 10: The termination condition.
  • next i++: The end-of-loop-iteration statement. Note ++ is always postfix in Cpp2.

I should add an example to the docs... I'll keep this open until I do that. Thanks!

@hsutter You closed this thread but it turns out that your answer left me with more questions! 😅

  1. I understand that one of the goals of cpp2 is simplification of the language through generalization and an overall reduction of the number of concepts. But in this case, having to revert to a while loop is a net loss in expressivity of the language. I we were to follow this principle dogmatically, all for loops would have to be eliminated because every for loop is just a special case of the more general and powerful while loop concept. However, the while loop is much-more error-prone, and I am sure you will agree that we don't want this kind of concept count reduction because having for loops in our toolbox enables us to better express our intent as programmers. For scientific computing purposes (I take this example because this is where I come from as a C++ programmer), not being able to express in a simple way index-based iteration patterns would be a deal-breaker. However, I do not advocate for the error-prone C-syntax either, but IMO having a concise syntax such as for idx_range(a,b) do (i){ ... } available is important to make cpp2 code safer. What do you think of it?
  2. I understand how the for loop syntax is built as for <range> do <lambda_expr>, which is actually very familiar to me as a HPC fellow, because we are used to writing thinks like hpc_framework::parallel_for( exec_policy, range, [&]( int idx ){ ... } ); in cpp1 syntax. However, the absence of the prefix : from the cpp2 lambda syntax in the cpp2 for loop syntax, combined with the fact that the cpp2 for loop syntax does not read left to right is a sign that this generalization is not very natural. I would also add on a personal note that I really don't like the do token, because it does not convey much meaning as a keyword, and is confusing because it connotes a do ... while loop. IMHO it is like having a then keyword after an if statement: it makes the syntax more verbose and does not provide any additional meaning. On top of that, having a do token justifies diverging the syntax from the if and while syntax which both require the body to be enclosed by curly braces. I would argue that having a coherent syntax among these 3 control flow structures should be a higher-priority goal than seeking unification with the function syntax. With this in mind, my question is therefore: why not opt for a more intuitive syntax for the cpp2 for loop? For example, Python's for i in range(N) is very natural and reads like english (they did a really great job on this one IMHO), and something like <optional label :> for <optional in(default), out, inout or move> <elm> : <range> { /* body with mandatory {} */ } would be simpler, more familiar, easier to read and more coherent with the rest of the cpp2 syntax? What do you think of it?

Anyway, thanks for the quick answer and the amazing work overall
Best regards,
Alex

Other related threads for reference: #432 #834 #386

Moving this to discussions (see #1073), as it seems more appropriate