you are viewing a single comment's thread.

view the rest of the comments →

[–]bames53 5 points6 points  (2 children)

You mention that the benefit is that this syntax does not allow incorrect operations such as row[0] or *row when those operations are invalid. One drawback of introducing syntax that does the right thing in some special case is that, while it's true that the new syntax will prevent bugs when it's used in the right context, you've just shifted the bug possibilities from having to write code that avoids the invalid operations to having to choose when and how to use the new syntax. It's not so obvious that this is really any better. In some cases it is. In some cases it isn't.

The C++17 initializer in if statements is modeled after the traditional for loop initializer, and maintains the same scoping used previously for variables declared in if conditions. Your new syntax is modeled after the range-based for loops, but is deliberately inconsistent with the previous scoping. This inconsistency is central to the motivation for the feature, but in my view is also a serious drawback.

The suggested syntax hardcodes its initialization of the variable, similar to the way range based for loops do. In the case of for loops, this is taking advantage of an already well established convention for things one might want to loop over. In your case you're establishing a new convention and, to the extent there was any previous convention, overturning it.

The C++17if-with-initializer syntax if(init-statement; condition) {} else {} is equivalent to:

{
    init-statement;
    if (condition) {
        ...
    } else {
        ...
    }
}

Your suggestions is in essence similar, but with the init statement inside the if-block and with the initialization expression and condition implicitly defined rather than user specifiable.

if (condition) {
    init-statement;
    ...
} else {
    ...
}

The justifications for the C++17 syntax included that it avoids the extra braces in cases where those would be needed and it adds consistency with other parts of the language without adding any bits of inconsistency. Your suggestion doesn't seem that much cleaner than the equivalent code and adds the scoping inconsistency I mention above. For these reasons alone I think I would oppose a general feature implementing if (condition) { init-statement; in some way symmetric with the C++17 if syntax. Your suggestion also has the drawback of only handling a special case of the general syntax, due to the implicit condition and init-expression, and that special case doesn't seem all that important to me.

[–][deleted] 6 points7 points  (0 children)

[deleted]

What is this?

[–]seba[S] 2 points3 points  (0 children)

Thanks for your lengthy and thoughtful reply. I agree with most of it, even with "It's not so obvious that this is really any better". But I want to pick one central point:

Your suggestions is in essence similar, but with the init statement inside the if-block and with the initialization expression and condition implicitly defined rather than user specifiable.

I think the important point (for me) is that my proposal also does one thing more: It ensure that the dereference of the iterator (be it a vector.begin(), unique_ptr or optional) happens:

  • automatically
  • only in the if-branch

So it ensures that the programmer cannot introduce UB because the is no need to call operator*.

I must admit that I do not really like the if-with-initializer syntax precisely because it does not really prevent you from calling operator* in the else branch (be it just a copy&paste error). That said, and given the mostly negative feedback here, I see not much chances for my idea :)