Go: proposal: Go 2: remove ++ and -- operators

Created on 1 Aug 2017  ยท  15Comments  ยท  Source: golang/go

The -- and ++ operators (called IncDec statements in the spec) are confusing for newcomers to the language. In other languages with similar syntax, ++ and -- can appear as either prefix or postfix expressions. However, in Go they can only be used in the postfix position and are statements, not expressions.

In that role, they are completely redundant: += 1 and -= 1 are statements with exactly the same semantics. Perhaps more importantly, += and -= in Go match the semantics of similar operators in other languages.

For comparison:

  • The Swift maintainers had the courage to remove their versions of these operators in Swift 3 โ€” and their operators were even the kind that match pre- and post-decrement operators in established languages, not redundant syntactic sugar.
  • Rust had the foresight to leave them out in the first place.
FrozenDueToAge Go2 LanguageChange Proposal

Most helpful comment

I don't think the stated benefits are anywhere near convincing enough to pay off for breaking every single Go program in existence (even if go-fix-able). Go 2 doesn't have the luxury of starting from a clean slate where these ideas might be more appropriate. Also, this is not Python.

All 15 comments

I don't think the stated benefits are anywhere near convincing enough to pay off for breaking every single Go program in existence (even if go-fix-able). Go 2 doesn't have the luxury of starting from a clean slate where these ideas might be more appropriate. Also, this is not Python.

I'd miss them in simple counting for loops, just for the reduced line noise. Maybe it's a good idea anyway, but I have a hard time convincing myself that this could be among the top three to five significant language changes that Russ indicated are budgeted for Go 2.

I'd miss them in simple counting for loops, just for the reduced line noise.

Yeah, I need to write up an experience report about loops one of these days: I'm not convinced that we should keep the three-slot for loop either, but that's a matter for another proposal.

I have a hard time convincing myself that this could be among the top three to five significant language changes

Agreed. It would have to be one of the minor changes, which I think also implies that it couldn't be the only one that requires a go fix. But if we end up needing to go fix most code anyway, it would be a nice change to piggyback.

It's easy to propose additions to the language, but that's how you end up with a complex behemoth like C++. Where I'm going with this proposal (and #21165) is that I think it's important that we also consider which parts of the language aren't pulling their weight: otherwise, Go 2 with be strictly more complex than Go 1.

(#20446 ("drop new") is along similar lines, but new, unlike ++ and --, isn't entirely redundant today: there is no existing expression that is a drop-in replacement at all call sites.)

++ and -- are here plainly for convenience. i += 1 is twice as long as i++ in number of characters and a bit more awkward to type.

It would be useful to have some statistics (say, over the std lib) about their use relative to loops and perhaps other operators.

i += 1 is twice as long as i++ in number of characters and a bit more awkward to type.

@griesemer I am not aware of any other features in Go that exist to save a handful of characters per operation. What is different about these operators that makes them exceptional?

The two closest examples I can think of are:

  • new, but it also allows the writer to omit an entire statement and variable when non-composite types are involved (and see also #148 and #20446); and
  • type-elision for values in composite literals, but the number of characters saved depends upon the type (it's not limited to 2-4 characters per expression).

It would be useful to have some statistics (say, over the std lib) about their use relative to loops and perhaps other operators.

Agreed. In particular, I suspect that we could make most existing uses of ++ and -- even more concise by expanding range loops to work with integer ranges.

https://github.com/josharian/gofor has a crude script and some four-year-old data in the readme. I doubt usage patterns have changed substantially since. I hacked it together long ago in preparation to write a proposal to expand range loops to work with integer ranges. (I ended up not writing it because I perceived it to be pointless, in light of some of Rob's comments on golang-nuts.)

@bcmills As I said, they are here plainly for convenience (the convenience being that they are shorter and easier to type than the equivalent). When we started with Go there was an (perhaps incorrect) understanding that ++ and -- are frequent and would be widely used (based on past usage in C, of course, where they are also there for convenience). Maybe that convenience is not that important anymore (range came later), and maybe there should be some range support for loops where we currently rely in ++/--. Statistics could shed some light on this.

I find "they're confusing to newcomers" a weak argument. The argument is backed by a link to an FAQ entry that suggests that our operators are confusing because they're less powerful than those in C. Based on that argument, a valid fix would be to make them more complex.

In reality, I don't think that these operators are confusing. People with no solid background in C-like languages can easily learn our definition of the operator, and people who do have said background are more than capable of relearning a small detail in a matter of minutes.

You're correct in pointing out that our version of the operator doesn't have any benefit over using += 1, other than a tiny amount of conciseness, and in isolation, that may be true. Removing the operators, however, would cause a lot of code churn, for IMO no real benefit in return.

Both Rust and Swift started with C-like operators and decided to remove them entirely, as opposed to adopting our definition. Going from very confusing operator to no operator has much higher payoffs than going from already simple operator to no operator.

Rust had the foresight to leave them out in the first place.

From the Rust FAQ:

Preincrement and postincrement (and the decrement equivalents), while convenient, are also fairly complex. They require knowledge of evaluation order, and often lead to subtle bugs and undefined behavior in C and C++. x = x + 1 or x += 1 is only slightly longer, but unambiguous.

The stated reason for avoiding the inclusion in Rust was confusing evaluation order (this seems to apply also for Swift); an issue which Go does not face as increment and decrement statements are not expressions.

I understand my comment is mostly noise, as @dominikh has already pointed this out. Just tried to frame the wording in a different way.

This change is the single stupidest thing Swift did. Let's not make the same mistake. It's a shame that the way they work in C has caused people to consider them harmful. But I don't buy the "it's too confusing for newcomers" argument, because a) Go makes them sufficiently different enough, and b) it's incredibly patronizing to assume that something as simple as "this increases x by 1" is too confusing to beginners. I know it's hard for us to do, but we need to not assume that beginners are dumb, and give them some show of confidence. After all, people who use the ++ and -- operators in C and C++ have at least learned how to use them well in 30+ years, to the point that we have useful idioms like *p++ = *q++ that most C/C++ programmers who aren't just starting to learn know what they mean instinctively (and if they are learning, they are almost guaranteed to encounter at some point during learning).

Which of these look most confusing to newcomers?

x /= 5
x >>= 5
x <<= 5
x *= 5
x %= 5
x = -x
x = +x
x += +x
x -= -x
x += 1
x -= 1
x++
x--

I think the ++ and -- are fruit hanging a bit too low. Seems like it would annoy more than benefit. Swift removed them from the language, which is a bit different than never having them in the first place.

Honestly? <<= and >>= might be the most confusing to beginners (note that I say beginners, not newcomers โ€” newcomers from other languages are likely going to be familiar with all of that, including ++), because they may not yet have the understanding of binary arithmetic; by comparison, it isn't hard to understand "this is shorthand for adding 1 to x".

Despite using these regularly Iโ€™d be ok with writing out x = x + 1.

// seems fine to me
for i := 0; i < len(a); i += 1 {

These operators are one more thing for new programmers to learn. We don't need them.

The benefits are not worth the drawbacks. While there are supporters, there are more detractors. Closing.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

OneOfOne picture OneOfOne  ยท  3Comments

gopherbot picture gopherbot  ยท  3Comments

mingrammer picture mingrammer  ยท  3Comments

bradfitz picture bradfitz  ยท  3Comments

jayhuang75 picture jayhuang75  ยท  3Comments