On Fri, Sep 11, 2020 at 6:29 AM Richard Hodges via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
On Fri, 11 Sep 2020 at 12:39, Garrett May via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
Hm .. who said,(in the context of C++ talk): "don't be clever unless you really have to"?  
I'm not really sure what that means?

Either way, my personal preference would be in support of Richard Hodges's suggestion. I've found GCC's expression statements to be useful in the past, and I think standardising it would be a perfect solution for this. It avoids the weirdness of having an initializer only for ternary operators that Ville Voutilainen mentioned (due to the syntax of ternaries) whilst also providing a way for scope to yield a value.

All that remains now is for someone to write a paper, in which is laid out the motivating use case, a demonstration that existing language features are limiting productivity and an impact assessment.

There is already a compiler supporting the feature, so that's in the paper's favour.

I suspect the biggest problems would be:
a) convincing everyone that the existing lambda syntax is not sufficient

Regarding statement expressions, I dislike deviations from the standard in Google's code, so I tried to get rid of statement expressions when adopted c++11 and got lambdas.  And indeed, lambdas solve much of the need.

But there was one strong outlier, and it looks like this:

std::optional<std::string> oldFindUsersCity(bool non_default) {
  std::optional<UserId> uid = UserId{};
  if (non_default) {
    uid = GetUserId();
    if (!uid) return nullopt;
  }
  std::optional<Location> uloc = uid->GetLocation();
  if (!uloc) return nullopt;
  return uloc->GetCityName();
}

Those if/return pairs make the code really ugly really fast, so people made macros:

std::optional<string> FindUsersCity(bool non_default) {
  UserId uid;
  if (non_default) ASSIGN_OR_RETURN(uid, GetUserId());
  ASSIGN_OR_RETURN(Location uloc, uid.GetLocation());
  return uloc.GetCityName();
}


And therein lies the problem.  These macros aren't that hard to implement with statement expressions (https://godbolt.org/z/G7Wsj3) , but it is not implementable with lambdas, given a desire to support either assigning to an existing variable or to new one, and given a desire to support:

  if (non_default) ASSIGN_OR_RETURN(uid, GetUserId());

Which is to say, ASSIGN_OR_RETURN can't expand to be a series of statements, because then the "if" would only apply to the first of those statements.  And you can't put the statements inside braces, because then assigning to a new variable would destruct the new variable when the scope introduced by the braces ends.

b) convincing other compiler vendors to bother to implement the feature.

Already done. gcc and clang and icc and Zapcc already implement it.  MSVC was the only one I tested, that didn't support it.  This is because there's a Unix header file that uses the feature. 

= - = - = - = - = - = - =

You forgot one thing, though.

(c) You have to address the nit-pickers who need to know how to handle the existing problems with statement expressions.

For one thing, there's the issue of destructors.  C++03 tightened the rules on when destructors were run, which was a big help.  But what happens when a temporary is used inside of a statement expression?  Is it destructed at the end of whatever statement (inside the statement expression) used it?  Is there an exception for the last statement in the expression?  Or are the destructors delayed until the statement expression's result is dealt with?

For another, we'll have yet another case where parenthesizing an expression changes its semantics.

For example, "max(1,2)" and "(max)(1,2)" do different things.  Because if max has been #defiine'd, putting parentheses around max will block macro expansion.

Likewise, "max(x,2)" and "(max)(x,2)" do different things.  Because ADL lookup will examine x's namespace for declarations of max... but only if max is *not* in parentheses.

And now, "{2, 3}" and "({2, 3})" will mean different things.

Note that the fact that parenthesization alters semantics is not a big issue except in the context of the use of macros.  However, as noted above, the use of macros is one area where statement expressions have high value, and macros tend to use extra parentheses to avoid syntactical surprises, so introducing a new syntactical surprise is not particularly welcome.

On Sat, Sep 12, 2020 at 2:26 PM Jason McKesson via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
True, but there now needs to be a justification as to why having an
expression issue a return (or other control logic) is an important
thing to be able to do. Most of the reasons to have
statement-expressions boil down to macro stuff, which we ought to be
getting away from, not encouraging.

I totally agree with you, Jason.  However, one thing I learned from being in the EWG room in person is that the idea that we "ought to be getting away from" macro stuff is not universally held.  There are plenty of silent supporters of macros who will not be impressed by a proposal whose primary motivation is "this allows us not to have to use macros".  (I think this is one reason why "if constexpr" can't be used to surround class or function definitions.  Sadly.)