Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
"Class" is the worst C++ keyword (nguillemot.blogspot.ca)
44 points by DmitryNovikov on Nov 26, 2013 | hide | past | favorite | 69 comments


I enjoyed this article; I learned several things (I didn't even know that "struct Employee : Person {" was valid syntax) and I can't argue with any of the factual content.

But this is a losing battle. "class" conveys intent to C++ programmers. There are lots of things that are needlessly complex in spoken languages (like do inanimate objects really need to be masculine or feminine?), but you can't just start speaking differently when the existing meaning is burned into people's brains.

As an example of existing convention, take the Google C++ Style Guide: http://google-styleguide.googlecode.com/svn/trunk/cppguide.x...

    Use a struct only for passive objects that carry data;
    everything else is a class.

    The struct and class keywords behave almost identically
    in C++. We add our own semantic meanings to each
    keyword, so you should use the appropriate keyword for
    the data-type you're defining.


Agreed. In the literal sense they are very much two keywords for the same concept, but culturally, a struct is POD and a class is not.

Personally I think the mistake was in making them the same. In Ides, a friend's LLVM-based PL (no contributions here, just some discussion and ideas), an instantiated 'struct' is a non-polymorphic object rather like in C#; this allows for more expressive code by logically attaching methods to the struct but without creating a vtable and breaking C compatibility.


No defaulting to private is not backwards. It enforces having a reason to make something public, which is a stronger default when it comes to building well abstracted, decoupled, modular code.

C++ doesn't come from the web era, where you can push code filled with bugs and fix them over time in a process that's seamless and invisible to the user. C++ comes from a time when software couldn't be changed once it was shipped, and so it was more important to strive for integrity over raw ease of coding.

Although I still don't see the argument for today's coding, as maintenance is the primary cost of web applications.


Precisely, C++ code is usually not riddled with all kinds of bugs and buffer overflows. </sarcasm>

This argument is so backwards. Having a garbage collector or a VM that ensures memory access safety, now that's what contributes to less bugs. Enforcing the freaking default visibility of class members to be private, does not. If you try to make this argument, which defies common sense, then show me some numbers.

And btw, good API design is not measured in the number of public members you have on a class.


> Precisely, C++ code is usually not riddled with all kinds of bugs and buffer overflows. </sarcasm>

Sarcasm aside: having more experience with C than C++, I find my C++ code rather significantly more resistant to buffer overflows, off-by-one errors, etc; it's when I'm interfacing with primarily C-based APIs that force me to do pointer math and so forth that I hurt myself. I don't have the confidence to write in C (fairly) quickly and correctly as opposed to C++. In this way C++ does come from that earlier era that the grandparent poster referred to: where Java didn't exist yet and the managed options weren't particularly fast, but C++ (even in its nascent form) could help you provide yourself tools for encouraging correctness that C could not.

Today, it's a different story. The STL (particularly as of C++11) is advanced to the point where it's very possible to write code that is, relative to Java or other managed languages, generally very fast and definitely very portable, while retaining pretty solid guarantees of safety. And I either I or the compiler are more likely to either notice my mistakes, which I inevitably make, in C++ than C.


You probably meant the stdc++, not the STL. But I agree, in C++11 one can use smart pointers which help avoiding many memory management pitfalls and make memory ownership mode more explicitly defined through the language itself.


In this case I did mean the STL-derived bits specifically. C++ collections, iterators and <algorithm> are awesome. When you're used to C for writing native code and your options are arrays, linked lists, or oh-god-I-hope-I-wrote-this-hashtable-correctly, this stuff is amazing. I guess they're not called the STL anymore, but I tend to use the term to refer to them specifically.

I actually only very rarely use smart pointers in my main C++ project; my game has a simple lifecycle and wouldn't benefit from them much, though I could probably stand to use unique_ptr more than I do. The primary place I use them is to use std::auto_ptr to clean up after myself when dealing with try-catch blocks--I standardized on them before really understanding unique_ptr and my use of them is single-function-limited so I kept it consistent. The game itself is modeled on a stack-based state machine and I'm able to pretty easily reason about my object lifetimes within each state without smart pointers.


People nowadays never mean SGI (or anything other than the C++ standard library) when they say "STL", so it's a good time to stop correcting them.


Still, it's not exactly correct. Unless you read STL as STandard Library.


bad_user why don't you go educate yourself and come back when you can make valuable comments. I've seen you trolling several posts now with comments that show your lack of Understanding of CS principles.

In your attack on my comment, you're starting to argue against something I'm not talking about or implying.

Good abstractions and code structure are created in a large part by being very careful about what's public. Defaulting to public helps a programming process that tends to ignore abstraction and structure, leading to heavy maintenance costs later. There's really no argument here, this is best practices established decades ago. It's fine to challenge establishments with new findings, but I find this article and your comments completely brain dead and unproductive because you're just lacking understanding of core principles.


Every C++ class declaration ever looks like this:

  class Foo {
  public:
   stuff;
  private:
   other stuff;
  };
What's the point of private-by-default if everybody overrides it anyways?


precisely! The default private is because of encapsulation! By default, every thing is private and you only provide access to specific things.


And yet, every class starts with public:, listing the public members. And in many cases the number of private things in the class is 1, for historical reasons due to how C++ (and C) manages "modules".


> Members of a class in C++ are private by default, but members of a struct are public by default.

It's not a bug, it's a feature. The idea is, you should always prefer private to protected and protected to public (by transitivity, private > public). This is good practice which helps build compact interfaces and maintain encapsulation.

Another reason to use "class" is because it's OOP terminology. There's no notion of "struct" in OOP (in fact, structs shouldn't even be there, they're an atavism).


> you should always prefer private to protected and protected to public

It's well known that protected is not any safer than public. Anybody can inherit and use it.

You can still make members private in structs. It's only less redundant:

  class X { public: stuff; private: other stuff; };
vs

  struct X { stuff; private: other stuff; };
> Another reason to use "class" is because it's OOP terminology. There's no notion of "struct" in OOP

That's cargo cult programming. Using "class" doesn't make your code OO. The language we are programming in is C++, not OOP.


> That's cargo cult programming. Using "class" doesn't make your code OO.

I shall proceed apace now to call

   var x = 5;
   (function() { return x + 2; })();
a glarfblork instead of a lambda, then, if semantics of naming should just be pitched out a window.


So... the main argument is that we can use "struct" instead of "class" so class is useless and awful, and that using "class" is brain-dead? And the author cites that use of class is absurd because it makes the default access-specifier "private", thus leading to more code?

Ok for a minute lets consider what this "more" code is. It is simply: "public:" when you want to start specifying the public members. You can even do this at the very start if you want ALL members to be public.

Now lets compare this to java or C# where (to the best of my knowledge), there isn't the ability to say "from here on, all members are private/public" and thus you have to give access specifier with EVERY member.

So the author can't be bothered to write "public:" once, but is ok writing public with EVERY member? Now THAT is absurd.


Correction: the default access level in C# I think is that the name is visible to all the members of the given assembly, but not outside of the assembly. I don't remember what it's called though.


And in Java it's package-visible.


Internal.


This is an awful article. It is extremily rare to choose `struct` vs `class` because of their default visibility. It is much more usual because of style.

Is it a functor? Is it a data structure? Do I need C-compatibility? Do I want to encapsulate behaviour and validate correctness? Do I want to maintain the company style?


"More verbose"? Just how... you tell me. A line? This no JavaScript/Coffescript land, this is freaking good old C++. Don't tell me about verbosity on this level.

Ah, and you found a gap in the template usage. Something not well thought. Some little case that the standard falls for it. Join the line, son. You got to understand and accept this. If you do you have a wonderful toolbox to architect whatever you want with it. If you don't you are another guy on the internet shouting that "C++ sucks".

Again, the analysis is interesting, but it misses the real deal when trying to make a point. Guy named Robert in the comment section does hit the nail by the head by the way. The real point is that structs are raw data structures while classes are fully featured OOP entities. Don't put they in the same box.


> structs are raw data structures while classes are fully featured OOP entities. Don't put they in the same box.

That's not true. Structs and classes are identical except for the minor functional differences highlighted in the article.


By the way C++ standardized it? Yes, the only big difference is property accessors.

By convention? Nope. The term struct pretty much stands for a pure data construct. C++ attempted (and pretty much failed) to make this distinction. Some languages, like C#, did a much better job.

In the real world we are always urging to being consistent. While other languages do a pretty good job by enforcing it, on C++ this is more on your shoulders.


I wish I could upvote this more than just once. Using 'struct' instead of 'class' and combining that with templated "pure functions" [1], when applicable, make for some really readable/maintainable/extensible C++ code, which, although often overlooked, is a multi paradigm programming language (the OOP proponents want you to believe otherwise ;-). Especially, as mentioned in the article, the fact that if you're honest you almost never really need private class members (that might later force you to create set/get-ters) really resonates.

These days, I prefer to create an interface using the PIMPL idiom [2] completely hiding the underlying implementation, whilst the implementation itself preferably consists of data structures and collections of these (hence 'struct') and some templated functions to modify these. This also resonates with an old C mantra: design data structures first, model functions after their behaviour or something similar [where I just cannot find a quote for].

My main gripe with using 'struct' in favor of 'class' is probably the compatibility problem with other programmers that might become confused as to why you are doing such weird things...

[1] https://en.wikipedia.org/wiki/Pure_function

[2] https://en.wikipedia.org/wiki/Opaque_pointer


The thing about templates is kind of silly, AFAIK, they added typename since the use of class didn't really make sense for the reasons he did state. They made an error in other words and corrected it in a latter release of the standard and best practice would be to use typename unless you need compatibility with an older compiler that doesn't support it.


> When forward declaring a class/struct, you must use the same keyword which it was declared with.

Wrong.

    struct Foo;

    class Foo {
    };

    int main(int, char**) {
            Foo f;
    }

compiles cleanly with -ansi -pedantic -Wall -Wextra besides warning about unused variable.


You don't mention what compiler you tested it with, but both Clang and MSVC are capable of spotting the mismatch (and sometimes even fail to compile it).



Thanks for confirming - this was the one statement that struck me as wrong too but I don't have a C++ compiler readily to hand on my iphone


Although it should be possible per standard C++, Microsoft's compilers have trouble dealing with it.


Although I can't currently support my claim, I swear that I have gotten compiler warnings for doing so.


I like to put the public interface of classes before the private implementation details. For this reason I always use struct. It saves some typing and decent C++ programmers know the difference. You cannot enforce any of these extra semantic meanings in code, so I consider them to be a waste of time anyways.


So when using a class as a struct (all public member variables and unless I missed it, no function), it's better to use the keyword "struct" rather than "class"? Say it ain't so...


To the best of my knowledge, you can use methods in a POD struct so long as it's not polymorphic. With no vtable, it'll be represented as a C struct would. It's not header-compatible with C, though.


You can. But my point is that as soon as you're using a class as an actual class rather than a struct, you'll probably have both public and private elements and at that point, I'm not sure any of the "advantages" described in the article are still relevant.


There are no rules to limit the kinds of member functions you can add to a struct. Structs can be polymorphic, can have vtables, and don't need to be compatible with C.


Yes, I know. As discussed elsewhere in this thread, there are cultural connotations to the term 'struct' that lead it to be used almost universally for POD, but--to ensure no ambiguity--that's why I said 'POD struct'.


Amen! Having programmed in C++ for close to 20 years now, I converged to using struct a while ago and yet to run into a case where it would create problems (some conditions apply, see below).

You want to make a part of a struct private?

  /* private */
Need a stronger deterrent?

  /* private, don't touch */
Need to protect against random people? Sure, only then -

  private:
But if you are working in the confines of a smaller team of people who read comments and generally abide by coding conventions that aren't enforced in the code, then it works beautifully and results in a slender and more readable code.


> You want to make a part of a struct private? > /* private * /

Thought this was a joke first, but it's not? Is it possible you have worked in the same place or with the same people a long time? I just can't imagine this would work for us.

And I thought about it quite some time, but I really cannot see why you would prefer a comment (ie ignored by compiler, same keyword but surrounded with a few extra keystrokes) by a true first citizen keyword that does the same and enforces it? That would be the same as comments saying "hey this is const" instead of using proper const-correctness, no?


If someone really wants to touch a private field, there's more than one way to do that. So "private" merely serves as a safeguard against honest mistakes. In this capacity it is a close sibling of that "if (0 == x)" contraption. It essentially says that I don't trust myself or others to not make dumb mistakes, so here's a safeguard for that. Not that it's a bad thing to have, but I can easily see that it can be deemed redundant to just having strong coding ethics.


"Coding ethics" stop buffer overflows too, right? ;-)


It's "discipline", not "ethics". I just had a brain spasm.

And, yes, it surely stops them better than some flimsy member access restrictions.


As opposed to a private array and a public iterator API?


Naughty hands will find a way to break a container/iterator metaphor just the same as a simple buffer. Point being is that it's much better to work with competent developers than to needing to rely an idiot-proof coding style.


Sure, and if you have a variable being accessed from different threads, just slap a comment on it:

/* SHARED BETWEEN THREADS! careful. */

I'm sure people will read it. And then write safe, reliable code.


Run-time concurrency issues are exactly the same as those of code design. Sure thing. Got anything else from where this came from?


I have worked on codebases (in javascript) that did essentially this.

I tweaked private members from outside the class.

I never regretted it.

There's probably a moral here, but I'm not sure what it is.


don't forget the ever-menacing leading underscore!


for tl;dr : class << struct. Struct inherits members publicly by default, is C compatible, and isn't ambiguous in forward declaration.


i dont think he gets c++


I'll tell you a secret - nobody gets C++

;)


it was just advertisement that targets java developers.


You can always

  #define private public
(!)


Game programmers are weird.


I'm not sure if it's game programming or C++ that makes him say what he's saying. I can't speak to his level of competence, but in writing my own game library (mostly for education, but also out of discomfort with tools like Unity) I have found myself ambivalent about visibility and find myself making a lot more stuff public than I otherwise would due to the (wonderful, why oh why don't more languages steal this) constness in C++. Constness can often replace private visibility for data--i.e., I don't need getters or setters. A field may be immutable once the object is instantiated, in which case I make it a const field, or it may be mutable, in which case the object's constness will handle it for me. (There's still the case where I need to perform transformations on a piece of data either on the get or the set, of course, and it's there that private usability is still of use.)

I came to C++ through a circuitous route and a lot of my early C++ is very Java- and Scala-influenced - private vars all over, getters, setters. I find my code becoming much more "public-first" as I get better at what I'm doing. That said, I'm uncomfortable with the idea of public being the default visibility; I think I do prefer to have to make that decision consciously while designing my APIs.


Constness is a really useful concept especially since it has been extended to also mean thread-safe (at least in the standard library), but has a bunch of design flaws that make it very difficult to use correctly.

1. It is not the default. Everything should be const by default and should be marked mutable when necessary. This even seems to be consensus in the committee and has been done for newer language features (lambdas).

2. It is not "deep" when pointers are used. This one is actually inherited by C, but still is really painful. This is fixed in D.

3. const_cast is legal C++ in most circumstances (the only exception being an object declared const). This invalidates most assumptions optimizing compilers could possibly make and takes away a lot of usefulness because there is always someone that is going to const_cast stuff around.

4. It becomes very hard to use with polymorphic types, because const-ness is part of the function signature and affects override behavior. Can you really safely say something about const-ness and thread-safety of all classes you could possibly derive? I often find I cannot and when I really need runtime polymorphism I will usually end up with lots of const-less member function.


1. Agreed.

2. Agreed. I like D, or I want to anyway. Main problem is the garbage collector; I'm writing a game that I want to port to mobile and I don't really trust a garbage collector in a low-perf environment. Rust is sort of interesting for that reason but is a few years from being mature enough to consider I think.

3. Also agreed for projects in the large, but for the most part I write C++ for me (for an idea of the project size, my utility game library is ~14KLOC over about 200 compilation units, the game will probably be around half of both) is all my code and so I have certain assurances. The only one I'd be hurting is me. And I am averse to that. =)

4. This I'm not really so sure about. I have never really run into this issue - my base classes are generally close to all-virtual whenever possible and only expose a fairly limited set of methods. I have run into what you describe--the deepest nesting of polymorphism I have is my current project is in my drawing code, where a DrawSource is basically a time -> (rect, textureID) mapping and a Sprite is a timekeeper for DrawSource that performs a little matrix manipulation before invocation and has a list of child Sprites. I solved this by pulling everything I didn't need out of Sprite entirely and presenting a very simple interface. (I'm liberated a bit in that this is all my code, though, so I generally know what types I have bouncing around.)

In any case, I'll take flawed C++ const over "new ImmutableCollectionBecauseWeDontHaveConst<T>(someList)" when I can. I like Scala quite a bit but this mutable/immutable division drives me up the wall.


There have been a lot of these articles lately...it seems to be fashionable to dislike OO and C++ OO specifically.

Not all committee's are bad and not everything they produce are bad. The C++ steering committee is made up of dedicated and sharp people...There are, at the very least, good reasons for most of their decisions.

You may not know the whole story just from your experience.

I'm just saying...


Worse than goto?


Yawn. C++ is terrible in myriad ways, it’s widely acknowledged; we’re just stuck with it for a little while longer until its replacements mature a bit. Besides, “static” is worse.

Edit: I didn’t mean to dismiss the article; I meant to dismiss C++. It’s unsurprising to C++ users that the language is complex; we should choose our battles carefully. Why complain about “class”, which is a relatively innocuous design bug, when other issues are so much more pressing? How do we balance immutable objects against move semantics? How do we relax constraints in the standard library for improved performance, while also enforcing constraints for correctness and safety? How do we migrate away from C++ when there are no viable alternatives?


Is it better than C?


The reduction of issues from scope-based destruction--and the simpler-to-reason-about resource lifetimes that come with that--and the ease of writing more indicative code via polymorphism without the mess that is something like GObject make me say yes, and quite strongly. Even setting aside everything else, that's enough for me to use C++ for any project where I have a heap (which is all my projects).


In certain ways, C++ is better than C. It has desirable features that C lacks. However, in certain ways C++ is worse than C, because the interplay of its many features creates much incidental complexity. For example, it was not feasible to write exception-safe code before smart pointers became ubiquitous. In addition, almost all the safety features of C++ are opt-in, when they ought to be opt-out.

I want a language like C, one that interfaces well with C, but with memory safety, static polymorphism, real vector types (to avoid the aliasing problem), and real higher-order functions, all with minimal runtime overhead. So I’m building one (Kitten). Mozilla (Rust) and several others (Nimrod) have similar ideas.


Nope. C rocks. C is way way more powerful. Yes, they don't really teach the power of C in Programming 101, but take High Performance Computing. That's all C


Define "powerful". Do you mean expressive power? If yes, I'm calling bullshit because C++ has all of the following (off the top of my head, and I won't even mention any OOP-y features):

1. Templates

2. Template-based standard library

3. Lambda expressions

4. std::bind

all of which make C++ much more expressive than C.

In terms of performance "power", there's almost no difference. Sure, calling a virtual method is slower than calling a function in C, but you don't have to "pay" for it with performance if you don't use it.

EDIT: god-dang formatting


HPC is not "all C"; there are very, very large Java and C++ presences in both the academic and financial HPC spaces.


And Fortran.


I'm planning to run simulations on GPUs using CUDA. What are pro/cons of going with C vs C++?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: