Skip to content

Fix Issue 2659 - Deprecate using the return of a comma expression#5737

Merged
yebblies merged 1 commit intodlang:masterfrom
mathias-lang-sociomantic:coma-operator-must-die
Jun 10, 2016
Merged

Fix Issue 2659 - Deprecate using the return of a comma expression#5737
yebblies merged 1 commit intodlang:masterfrom
mathias-lang-sociomantic:coma-operator-must-die

Conversation

@Geod24
Copy link
Member

@Geod24 Geod24 commented May 7, 2016

The comma operator is a constant source of confusion / bugs.
In all use case, code using comma operator can be rewritten without hurting readability. The exception is the increment part of for loops, where it is pretty handy.
This P.R. introduce a deprecation message for every usage that isn't in a for loop increment.

Example of fixes needed outside of DMD:

Note:
There were some CommaExp in the test that I had to silence using -d.
The underlying reason is that deprecations message shouldn't require those tests to change (and the change was pretty big since I would have had to update all line numbers of error messages...).

Ultimately, in for statement, I think we should recommend using something along the line of { a.popFront; b.popFront; } instead, but it shouldn't introduce any performance hit, which is not currently the case.

Mandatory ping to @andralex / @WalterBright as this is a language change.

@dlang-bot
Copy link
Contributor

Fix Bugzilla Description
2659 Remove the comma operator

@Dgame
Copy link

Dgame commented May 7, 2016

So, e.g. this code would trigger a deprecation warning?

int a, b, c;

That would make it rather hard to convert C-Code to D..

@Geod24
Copy link
Member Author

Geod24 commented May 7, 2016

@Dgame : That's multiple declaration, and it's fine. Look at L28 on the changelog where it's used.

@yebblies
Copy link
Contributor

yebblies commented May 7, 2016

I think we can disallow x = a, b but allow a, b - this should catch all bugs without breaking so much code. This rule will let for increments work without a special case.

@Geod24
Copy link
Member Author

Geod24 commented May 7, 2016

I think we can disallow x = a, b but allow a, b - this should catch all bugs without breaking so much code. This rule will let for increments work without a special case.

That's reasonable. However it looks like a bigger special case to me than the proposed solution. In addition, a, b should be trivial to rewrite as a; b;.

@schveiguy
Copy link
Member

@yebblies you mean disallow usage of the comma expression result, or specifically assignment? Because I think this is also bad:

void foo(int x) {}

void main()
{
    int a, b;
    foo((++a, b));
}

@schveiguy
Copy link
Member

And of course the example from TDPL and Ali's talk:

synchronized(locka, lockb) // only locks lockb
{
}

@yebblies
Copy link
Contributor

yebblies commented May 8, 2016

Disallow using the result.

@schveiguy
Copy link
Member

@Geod24 We can go in stages. First may be as Daniel specified, then deprecate such statements and suggest the obvious fix. Then remove comma expressions altogether (except for loop increments of course ;)

If we eventually end up using comma for expression tuples, then we can move the for increment clause into being a tuple.

@mathias-lang-sociomantic
Copy link
Contributor

@Geod24 We can go in stages. First may be as Daniel specified, then deprecate such statements and suggest the obvious fix. Then remove comma expressions altogether (except for loop increments of course ;)

That's a possibility. Before going down any path, we should probably assess how needed it is. Separating deprecation in different stages only makes sense if it significantly reduce the cost of transitioning for user code. If the occurrences are low enough, splitting it in multiple release might induce higher costs. Should we take this to the NG ?

@schveiguy
Copy link
Member

schveiguy commented May 9, 2016

It may be a case of creeping acceptance. Whereas saying "we are going to remove all uses of comma operators" may be taboo, saying "we'll remove only the really bad uses of comma operators". Then if we don't get to the holy grail of eliminating comma operators (or reinterpreting them as equivalent feature such as tuples), at least we have some improvement that fixes a ton of bugs. But eliminating the bad uses may reveal that we can later easily move people on board the no comma train.

But let's discuss as whole community.

@schuetzm
Copy link
Contributor

schuetzm commented May 9, 2016

See also #3943 and #3399 for previous discussions.

@yebblies
Copy link
Contributor

yebblies commented May 9, 2016

The idea is that if a,b was a tuple, then
for (;; a,b)
would still work, but
x = a, b
would not.

So code that relies on the type of a comma expression would break, but code that just relies on both arguments being evaluated would not. It has the additional (and somewhat more urgent) benefit of eliminating most comma expression bugs.

@mathias-lang-sociomantic
Copy link
Contributor

@schuetzm : Thanks for the links and the previous attempts, third time's a charm!

It has the additional (and somewhat more urgent) benefit of eliminating most comma expression bugs.

And that is the motivation behind this P.R.

I'm not proposing anything related to built-in tuple here. I propose that we deprecate a construct that is known to cause bugs, and that provides little to no advantage over the other, much more common construct(s), except in one single case which is not deprecated.

If we make this enhancement depends on the future of the comma operator for tuples, we can already close this P.R. because it's not going to be merged.

Regarding code breakage, again we should assess how much code is impacted. I didn't find any occurrence in Phobos (because they use Dscanner, thanks @Hackerpilot ), and only 3 in Druntime, one of which was a bug.

@ntrel
Copy link
Contributor

ntrel commented May 10, 2016

Regarding code breakage [...] only 3 in Druntime, one of which was a bug.

#3943 would detect all comma bugs without breaking code like:

if (foo)
    x++, y++;

Despite there being a trivial fix, it seems better not to risk breaking anyone's code, particularly when this pull probably doesn't simplify the compiler/language more than #3943. I agree ideally we would merge this pull, but for stability it's better to be conservative and never break people's code without good reason.

@ntrel
Copy link
Contributor

ntrel commented May 10, 2016

Furthermore, there's the argument about making C/C++ code harder to port for no reason.

@mathias-lang-sociomantic
Copy link
Contributor

#3943 would detect all comma bugs without breaking code like:
[snip]
I agree ideally we would merge this pull, but for stability it's better to be conservative and never break people's code without good reason.

I agree we should not make hasty decisions, or taking unreasonable path when changing the language. But this is not an on the spot decision, it's been discussed for at least 7 years.
Also, when it was discussed at DConf, @WalterBright mentioned that the deprecation would have to last for a while.

So far the thread on the forum only consist of yea, and I've yet to see a code construct that cannot be trivially rewritten and/or doesn't look better.

@yebblies
Copy link
Contributor

The solution I've outlined before has the enormous advantage of being pre-approved.

src/parse.d Outdated
}

Expression parseExpression()
Expression parseExpression(bool allow_commaexp = false)
Copy link
Contributor

@wilzbach wilzbach May 15, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this parameter useful if it just prints a deprecation warning and wasn't used before?

@mathias-lang-sociomantic
Copy link
Contributor

@yebblies : I gave a shot at implementing a deprecation on using the return type of the CommaExp.
However I couldn't find an obvious way to do it. Any suggestion that doesn't involve changing the semantic (based on a switch or not) ?

@yebblies
Copy link
Contributor

I'm not sure it's possible without changing semantic a little. My suggestion would be to have a flag in CommaExp and set it from the enclosing exp/statement when it's ok, then in CommaExp.semantic give an error if the flag isn't set. I don't think there are many contexts where an expression result isn't used.

@mathias-lang-sociomantic
Copy link
Contributor

The idea is that if a,b was a tuple, then
for (;; a,b)
would still work, but
x = a, b
would not.

Both cases still work, because the second case assign 'a' to 'x', not 'b', so this should work if we don't want to break 'legit' code.
Surely you meant x = (a, b) ?

Anyway, updated (sorry for the delay).

@mathias-lang-sociomantic
Copy link
Contributor

Only occurrence left: dlang/phobos#4348

@yebblies
Copy link
Contributor

Both cases still work, because the second case assign 'a' to 'x', not 'b', so this should work if we don't want to break 'legit' code.
Surely you meant x = (a, b) ?

Something like that.

@mathias-lang-sociomantic
Copy link
Contributor

Fixed, now green.
The test is in compilable because it would only produce one error message with -de.

@yebblies
Copy link
Contributor

Please move the removal of comma exps in dmd's source and test suite into another PR.

@Geod24 Geod24 changed the title Fix Issue 2659 - Deprecate comma expressions outside of for increment Fix Issue 2659 - Deprecate using the return of a comma expression May 27, 2016
@Geod24
Copy link
Member Author

Geod24 commented May 27, 2016

Renamed the P.R. + rebased on master

@Geod24
Copy link
Member Author

Geod24 commented May 31, 2016

Ping @yebblies @9rnsr @WalterBright : How does that look to you ?

changelog.dd Outdated
module comma;

void main () {
size_t aggr;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick - indentation seems a bit off.

@mathias-lang-sociomantic
Copy link
Contributor

Updated according to @ZombineDev 's comments.

src/statement.d Outdated
statements.insert(i, flt);
continue;
}
// Allow CommaExp in ExpStatement because return isn't used
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why isn't this part of ExpStatement.semantic?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be worth encapsulating this check-and-set pattern into a function, eg discardCommaResult that walks the expression tree if necessary.

@mathias-lang-sociomantic
Copy link
Contributor

Updated

{
/// This is needed because AssignExp rewrites CommaExp, hence it needs
/// to trigger the deprecation.
const bool isGenerated;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't actually private in D. I'd suggest just leaving it public, we're not systematically using member protection yet in D.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One has to start :)
Removed it from the C++ file.

@yebblies
Copy link
Contributor

Auto-merge toggled on

@yebblies yebblies merged commit 0a7f87a into dlang:master Jun 10, 2016
@mathias-lang-sociomantic mathias-lang-sociomantic deleted the coma-operator-must-die branch June 10, 2016 12:04
@mathias-lang-sociomantic
Copy link
Contributor

Yay ! Thanks a lot :)

@andralex
Copy link
Member

This is awesome!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.