8 ms·
I think that at this point, C++ has basically to be treated the same as the English language. Sure, you could write sentences that span three pages, employ Shak
by 4bpp 8y ago
I think that at this point, C++ has basically to be treated the same as the English language. Sure, you could write sentences that span three pages, employ Shakespearean vocabulary or words that hardly anyone has known since the abolition of Classics from university admissions tests, or encode another layer of meaning in the bit pattern of when you do and when you don't use Oxford commas. What makes something good English communication is not whether you used those features correctly, employed the most in vogue ones or found the "most elegant abstraction" ("there's this one word attested in a handful of 14th century sources that captures exactly what I want to say, so I'll use it without explanation"), but whether you have struck the right tradeoff of minimising the combined effort put in by you and your audience and conveying your message faithfully.
Of course, for English, this is exactly the sort of problem that is addressed by style guides (and teachers/peers reacting to you, and natural selection). I think what we need is more and better opinionated C++ style guides that don't just talk about what line to place your { on, but have the confidence to say things on the level of "std::move may add a marginal amount of efficiency, but greatly detracts from the legibility of code. Avoid using it altogether."
- Aardappel 8y agoThere should probably be two C++ styleguides: one for library authors and one for library users. For the former, use of std::move can be absolutely essential to abstractions that are both efficient and correct. For the latter, it probably means you're overthinking things.
- 4bpp 8y agoThis is a fair point, but I still feel like there should be some regulations on how it is used in libraries (lest we wind up in a "this chunk of code is going into a .so, so everything goes!" situation), since library code still has to be read and maintained. Compare inline assembly: it can be absolutely essential to talk to hardware or use specialised processor features (like if you want to use fancy SIMD instructions in the inner loop of a linear algebra library), but everyone would probably agree that a library which keeps the actual assembler code contained inside one or two specific functions is somehow preferable to one where each of the 40 different ways of calling it happily start out with an __asm block that packs their respective arguments into the relevant special-purpose registers and only then call the common "do the actual processing" function.
- 4bpp 8y agoPersonal opinions on the "right subset" of C++: * Yes to classes. * Yes to inheritance and virtual member functions, because interfaces are a very useful and easy to understand abstraction. Moreover, especially for games, idioms such as "class Monster : public DamageableObject" are really the most natural thing. However, avoid situations in which you need dynamic_cast like the plague. No to virtual inheritance. - I really wish class memory layout were standardised more, but at least some non-standard assumptions are fairly safe in my experience: e.g. class A : B {...} ... B * x; assert((long)static_cast<A* >(x) == (long)x); * Before you start using "friend class", consider whether you could get around it somehow. If a class is not public-facing, set everything public and enforce encapsulation by self-discipline rather than language features. * Yes to templates in their C++ 101 application of making a $type-specialised version of classes and functions. No to using them to perform any real compile-time computation, or anything of the type Boost pulls. No to Boost. * "Keep the parts of your code that only do C stuff in C". - printf over iostream. - (de)allocate classes with new/delete, but POD with malloc/free - exception: std::string over char* , because it is really that much more convenient * Yes to lambdas, but only pass them as function arguments if there is no good alternative, because of legibility. Avoid stuff like the for_each(..., []{ ... }) in the Ranges example. * Yes to STL containers and algorithms, because everyone knows how they work and they are usually good enough. * Range-based for over for(std::container::iterator i=...). Using the Ranges TS when a plain for loop would do strikes me as novelty-chasing and violates "do C stuff in C". * Cautious yes to auto. It does somewhat detract from comprehension in some use cases. Don't just auto everything because you are too lazy to figure out the type. * std::shared_ptr only when you actually think you can't answer the question of what the appropriate point to deallocate a piece of memory is, or at least not without significantly changing the structure of your code. * Avoid std::tuple, std::variant and other awkward STL attempts to replicate functional language idiom without the syntactic support. It's terrible to read. Unfortunately, STL containers sometimes force you to use pair. * No to exceptions; their interaction with other language features is awkward, and the eternal difficulties with platform support make me feel no confidence in the reliability of the feature. (I'm unfamiliar with the bowels of the implementation, but it seems like unwinding C++ stacks is fundamentally a hard problem.) * No to novelty features such as user-defined literals. * goto only to break out of multiple levels of nested loops. * Coroutines strike me as something that's unambiguously cool but so far removed from the standard idiom of C++ programming that I'm inclined to say no. Maybe there's an alternative style guide you could write that says yes to coroutines and no to some of the things above. Multi-paradigm should not mean "use all the paradigms". (I'm very happy to be persuaded otherwise on any of these points.)