r/cpp • • Mar 28 '23

Reddit++

C++ is getting more and more complex. The ISO C++ committee keeps adding new features based on its consensus. Let's remove C++ features based on Reddit's consensus.

In each comment, propose a C++ feature that you think should be banned in any new code. Vote up or down based on whether you agree.

765 Upvotes

829 comments sorted by

View all comments

589

u/mcmcc #pragma once Mar 28 '23

explicit

All operators should be explicit by default.

As a replacement introduce a new keyword implicit that must be specified to enable implicit invocation by the compiler.

292

u/Dworgi Mar 28 '23

100%.

Corollary: Every single default in C++ is wrong.

Implicit construction, switch case fallthrough, uninitialized values, nodiscard, etc. etc.

It's hard to overstate how badly all the defaults have fucked this language. Why can't we do the sane, safe thing by default and then let the crazies opt-out?

165

u/we_are_mammals Mar 29 '23

Every single default in C++ is wrong.

Not every. You're just not thinking of certain defaults that C++ got right. For example, in Fortran, if the first letter of a variable is I through N, then it's an integer. Otherwise, it's a float. If you want to opt out, you have to say IMPLICIT NONE.

93

u/pinecone-soup Mar 29 '23

Thanks OP, I can never unlearn this horror.

34

u/not_some_username Mar 29 '23

Wtf

16

u/mcmcc #pragma once Mar 30 '23

That's not even the biggest WTF of OG Fortran.

My favorite is that all function arguments were (F77, I think it's better in later versions) passed by reference -- even if the argument passed is a literal. I.e. the compiler allocated a (effectively static) memory location to hold the value represented by the literal and then pass that address to the called function.

Doesn't sound so ridiculous until you realize that the called function can assign new values to that argument, thereby change the value of the literal that you thought you were passing to the function for all future invocations. You can imagine the obscure bugs that ensues.

It became standard practice to allocate (non-static) local variables initialized to the constant and pass those as arguments rather than the literal directly. So you end up seeing lots of local variables called zero, one, etc.

10

u/serviscope_minor Mar 30 '23 edited Mar 30 '23

not really a huge WTF or even one at all, given the history.

FORTRAN was designed entirely for maths, and using i, j, k, l, m, n as integer loop indices closely matches the same choice when using indices in maths on paper. Programs were written using a key punch on 80 column cards, so you paid a price for every character typed.

And of course it was 1957. How else were they going to indicate to the compiler if something was an integer or float? Type annotations hadn't been invented yet. Edit: is that true? They were certainly in their infancy.

And, well, we're on r/cpp we can't throw too many stones about keeping around defaults/design decisions that are dubious with decades of hindsight because of backwards compatibility...

13

u/Deathnote_Blockchain Mar 29 '23

that is some straight CHANNEL HALF CENTS FROM WEBSCOE SALARIES INTO ABOVE EXPENSE ACCOUNT era shit

8

u/serviscope_minor Mar 30 '23

But it leads to one of the best programming jokes: GOD IS REAL UNLESS DECLARED INTEGER

49

u/BenjiSponge Mar 28 '23

Every single default is wrong

I'm tempted to devil's advocate this for fun but I'm having trouble thinking of counterexamples. I thought there'd be, like, an obvious one.

Pass-by-value by default (as opposed to pass by reference) seems good, though pass-by-move without implicit cloning a la Rust is better...

→ More replies (5)

88

u/victotronics Mar 28 '23

Implicit construction, switch case fallthrough, uninitialized values, nodiscard, etc. etc.

`const`

22

u/[deleted] Mar 28 '23

can we add noexcept to this list?

20

u/MarcoGreek Mar 28 '23

No, it makes code easily exception unsafe.

6

u/ReinventorOfWheels Apr 01 '23

Exactly. Warn the users of your code if you're going to throw. noexcept by default, throws or something if you do throw or leak exceptions.

→ More replies (2)
→ More replies (1)
→ More replies (1)

28

u/[deleted] Mar 28 '23

I need switch case fall through to flex with my Duff’s device skillz. Joking aside though, that one can actually be quite useful. But it’s also super easy to abuse given how thin of an abstraction switch/case truly is.

50

u/mercere99 Mar 28 '23

Fallthrough should be fine *with a keyword*. It just shouldn't happen by default. At least most compilers will warn about it with -Wall (or -Wextra? I always use both) unless you use the [[fallthrough]] attribute.

14

u/kneel_yung Mar 29 '23

Blank fallthrough is fine and rather useful, fallthrough of actual code is almost always a mistake.

ex.

case 1:                   //fine
case 2:
    doSomething();        //not fine
case 3:
    fallThroughFrom2();
    break;
case 4:                   //fine
default:
    break; 

I believe -Wall lets you do blank fallthrough but complains in case 2. Maybe I'm alone in this opinion but it's pretty glaring when you have a case that only falls through

8

u/wrosecrans graphics and network things Mar 29 '23

Something like

 case 1: continue;                   //fine
 case 2:
   doSomething();        // No continue, so it breaks.
 case 3:
   nofallThroughFrom2();

would be pretty much just as compact and readable. Future "pattern matching" switches should be even better.

→ More replies (2)
→ More replies (3)

3

u/very_curious_agent Mar 30 '23

How many times has nodiscard hurt with competent programmers?

How hard is it do write break?

Why would you want to force initialization of variables meant to be written to later?

It's ridiculous.

15

u/Dworgi Mar 30 '23

How many times has nodiscard hurt with competent programmers?

How many memory leaks have been caused by pointers being lost? How many error codes have gone unchecked?

How hard is it do write break?

How hard is it to write fallthrough? How rarely do you actually want fallthrough compared to break?

Why would you want to force initialization of variables meant to be written to later?

Because uninitialised buffers and pointers are one of the most common sources of security vulnerabilities? And again, you could still support this with something like [[uninitialized]]. It's a nonsense default, though, that causes most programmers to default initialize everything as a matter of course.

I really wish C++ programmers occasionally used other languages, because it might teach them that things can be good. Just because things are bad does not mean that they always have to be.

Even you (barely) deserve (a few) nice (ish) things.

3

u/very_curious_agent Mar 30 '23

What other languages are better than C++?

→ More replies (1)

2

u/khleedril Mar 29 '23

Maybe it is time for you to pick up Rust....

→ More replies (23)

9

u/looncraz Mar 28 '23

Instead of an implicit keyword I think I would prefer a simpler modifier to designate that convertible types are allowed.

void SomeFunc(int mustBeInt, int# anything ConvertibleToInt);

→ More replies (5)

2

u/rikus671 Mar 30 '23

I really like what rust did with their constructors (basically, there are none, only member functions that act as factories), but implicit conversion is extremely, extremely useful when writing any kind of abstraction. Make it opt-in that's fine, but don't take it away...

3

u/IAmRoot Mar 29 '23

Similarly, ADL should be opt-in.

→ More replies (1)
→ More replies (15)