You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[SUGGESTION] Definite first assignment to return this #368
At #366 (comment),
we discovered that a definite first assignment has type void.
Returning an lvalue reference to the object parameter
is only a convention in user-providedoperator= (C++𝘕).
That's the language's default,
and what is expected of a regular type.
There should be worth in Cpp2 unifying not only syntax,
but also the semantics of its operator=.
This should eliminate future guidance
around a first assignment behaving differently on whether it's definite.
It should be worth noting that
the C++1 methods to delay object creation
return a reference or pointer to the created object.
The C++ standard library follows suit,
and I can't come up with a reason for Cpp2 not to.
There should be worth in Cpp2 unifying not only syntax,
but also the semantics of its operator=.
Thanks. I agree with being consistent.
But (contrarian here) I was actually thinking of going the other way:
Option 1: Have assignment return void which would disallow chained assignments. I vaguely remember discussing that here in another issue(?) where I think someone came up with an example where operator= returning non-void was useful for something other than chaining, but I don't remember it now. But, as you point out, an operator= that returns void breaks std::assignable_from.
and/or
Option 2: Leave assignment alone for Cpp1 compatibility, but disallow writing chained assignments in Cpp2 code.
I think Option 2 is a good thing to do regardless, so I'll do that now...
Re this:
This does mean that, like assignment, an initializing =expression-statement will have to be discarded.
s: std::string;
_ = s = "";
I don't understand? Assignment does not have to be discarded, s = ""; is fine.
I agree that whatever is done here, we should not require discarding the result of an = value-set statement, whether it's a definite first use or not. Having to discard an assignment would be weird. (And Option 2 above would actually ban writing that, which I think is an improvement.)
This does mean that, like assignment, an initializing =expression-statement will have to be discarded.
s: std::string;
_ = s = "";
I don't understand? Assignment does not have to be discarded, s = ""; is fine.
I agree that whatever is done here, we should not require discarding the result of an = value-set statement, whether it's a definite first use or not. Having to discard an assignment would be weird. (And Option 2 above would actually ban writing that, which I think is an improvement.)
I vaguely remember discussing that here in another issue(?) where I think someone came up with an example where operator= returning non-void was useful for something other than chaining, but I don't remember it now.
That was it, thanks! Browsing that, the additional use case mentioned there was using the result as an lvalue, such as while ((ch=getchar()) != EOF).
So I think the remaining question for this issue, after the above commit to make assignment and discarding more regular, is whether we want to keep the issue open to allow definite first uses like this:
s: std::string;
(s = "xyzzy").append(" or plugh");
I see arguments for both that the above should be supported and that the above should be banned...?
The specific use case of while ((ch=getchar()) != EOF) could not be a definite first use anyway, because it's in a loop.
So I think I've come down to that a definite first use initialization should be a whole statement, not a subexpression. TODO: I should create a diagnostic for that so that a violation gets a nice readable error message
Activity
JohelEGP commentedon Aug 8, 2023
This does mean that,
like assignment,
an initializing
=expression-statement will have to be discarded.hsutter commentedon Aug 11, 2023
Thanks. I agree with being consistent.
But (contrarian here) I was actually thinking of going the other way:
Option 1: Have assignment return
voidwhich would disallow chained assignments. I vaguely remember discussing that here in another issue(?) where I think someone came up with an example whereoperator=returning non-void was useful for something other than chaining, but I don't remember it now. But, as you point out, anoperator=that returnsvoidbreaksstd::assignable_from.and/or
Option 2: Leave assignment alone for Cpp1 compatibility, but disallow writing chained assignments in Cpp2 code.
I think Option 2 is a good thing to do regardless, so I'll do that now...
Re this:
I don't understand? Assignment does not have to be discarded,
s = "";is fine.I agree that whatever is done here, we should not require discarding the result of an
=value-set statement, whether it's a definite first use or not. Having to discard an assignment would be weird. (And Option 2 above would actually ban writing that, which I think is an improvement.)Reject chained assignment, don't emit `[[nodiscard]]` on = and ?= (See …
JohelEGP commentedon Aug 11, 2023
You're right.
I was actually thinking of compound assignment,
which do require discarding: https://cpp2.godbolt.org/z/rGddsxGcK.
JohelEGP commentedon Aug 11, 2023
I remember isocpp/CppCoreGuidelines#1988.
A quick look suggests that's your reference.
hsutter commentedon Aug 11, 2023
Yes, my commit just now "fixes" that for
?=too. 😎 So this is a consistency improvement where=and?=are now treated the same.hsutter commentedon Aug 11, 2023
That was it, thanks! Browsing that, the additional use case mentioned there was using the result as an lvalue, such as
while ((ch=getchar()) != EOF).So I think the remaining question for this issue, after the above commit to make assignment and discarding more regular, is whether we want to keep the issue open to allow definite first uses like this:
I see arguments for both that the above should be supported and that the above should be banned...?
hsutter commentedon Aug 12, 2023
Adding to the previous comment:
The specific use case of
while ((ch=getchar()) != EOF)could not be a definite first use anyway, because it's in a loop.So I think I've come down to that a definite first use initialization should be a whole statement, not a subexpression. TODO: I should create a diagnostic for that so that a violation gets a nice readable error message
JohelEGP commentedon Aug 12, 2023
That's certainly consistent with definite first use initialization of data members in
operator=.Reject chained assignment, don't emit `[[nodiscard]]` on = and ?= (See …
Require definite first use initialization to be a standalone statement,
Require definite first use initialization to be a standalone statement,