
Why C++ sucks (2016 edition) - ingve
http://dorinlazar.ro/why-c-sucks-2016-02-edition/
======
beat
I go a little deeper and more esoteric with my big gripe with C++... _why can
't it be parsed with a simple LALR(1) parser_?

Donald Knuth summed this up much more elegantly than I could ever hope to do
so, in his six character critique of C++:

a < b > c;

 _What the hell does that mean_? What it means is that you cannot determine
the meaning of those six characters without knowing in advance the types of a,
b, and c. Is it an odd-but-valid C comparison? (a is less than b and b is
greater than c) Or is it a template declaration? You cannot know these things
without context.

Back when I studied compiler theory and was reading the Dragon Book, the
simplicity, elegance, and precision of the LALR(1) parser design really
touched me. And it was implemented on every Unix box with lex and yacc. This
is how you write a compiler! This is how you understand structure precisely!
To be syntactically valid, a statement must have one and only one meaning.

C++ cannot be parsed without interpreting variable types at parse time.
LALR(1) does not work. It never has worked. C++ has been broken on this front
since the 1980s, when it was just a preprocessor that cross-compiled to C.
Why? What possible benefit is there to giving up that core bit of parser
discipline?

"Because it's _powerful_!", someone sneers, as if that condescension justified
bad design. "Because templates are so hard!" another whispers. But what about
this?

a [< b >] c;

If the template declaration tokens were [< >] rather than < >, they wouldn't
overload the comparison operators. The meaning of Knuth's example would be
unambiguous, and both could be parsed without grief - both by machines, and by
human eyeballs. This isn't difficulty. It's just not thinking through the
consequences.

But that's okay. Smoke enough of that << and >> crack, and you'll soon forget
those tokens are bitwise shift operators, not i/o. Sigh.

~~~
zzalpha
Of all the complaints I can think of regarding C++, the one I care least about
is the difficulty in disambiguating the grammar... Languages exist to help
humans, not compilers. Of course, C++ often fails in that regard as well.

Aside, a pox on the house of bottom up parsers. Anyone trying to produce
useful semantic errors out of a bottom up parser understands how god awful
they are to work with. There's a reason both GCC and clang use hand rolled
recursive descent parsers...

~~~
bjz_
> Of all the complaints I can think of regarding C++, the one I care least
> about is the difficulty in disambiguating the grammar

Compile time speed? Refactoring? Jump-to-definition? Autocomplete?
Intellisense? Those are all important for UX, and a tricky-to-parse grammar
makes those things mighty challenging.

~~~
roel_v
Visual Studio does an almost-perfect job of this, and what is missing is not
because of the parsability of C++. What's your point?

------
fsloth
I'm sorry, but from the point of view of technical merit these opinion based
rants are starting to feel really disingenious.

Scott Meyers has written lots of good stuff on how to use C++ properly.

Yes, C++ is the rocket-octopus in a razor armour, equipped with automatically
foot targeting shotguns and all the rope to hang every developer twice.

Yes it the best tool everywhere? No. Is it my favorite language? No. Is it
absolutely essential for value producing programmers around the globe? Yes.

The thing is, the rocket-octopus infestation is so wide that we've learned to
use it to our advantage (after a few missing foots but hey - rockets!) and
understood how to deal with it's kinks and warts. We've got pretty good tools
to wrangle it (Visual Studio is actually pretty good, IMO), and boy, can it go
places.

The ecosystem is the main reason it's as alive today as it is. I would much
rather take my iridescent paradise bird F# to work, but the sad thing is, the
poor thing does not survive yet everywhere where the rocket octopus does. My
pet python is much more well behaved but unfortunately it still does not have
hassle free rockets nor can it survive in high performance scenarios with even
more wrangling than the octopus does.

~~~
Negitivefrags
You know what? I'm going to take the controversial opinion that C++ is both
the best tool for everywhere and my favorite language.

C++ really has only one downside. It's hard to learn. Almost all complaints
about it really boil down to not knowing the language well enough.

But so what? Because once you know it well...

Once you know C++ really well, you understand what it means to have no
compromise.

It has the best performance and the highest level abstractions in one package.

It has both amazing safeguards against programmer error and the ability to
break all of them if you need to.

It has great portability while still giving you full access to all he platform
specific features.

You can feel just as at home writing a web browser or a website in C++.

I could go on.

You get all this good stuff and really it only really takes a few years of
seriously using the language to get that good. What is a few years in a 40
year career?

Also, don't believe the bullshit of "nobody really knows C++" that a lot of
people claim. You can find dark corners of any language. The reason they are
dark corners is because they don't come up in real code.

~~~
loup-vaillant
> _It has the best performance and the highest level abstractions in one
> package._

The highest level abstractions, are you kidding me?

I am currently writing a little interpreter in C++. I would have used Ocaml,
but the rest of the project is in C++. Well, just try to write an abstract
syntax tree in C++. In languages such as ML and Haskell, this is easy:

    
    
      type expression = Litteral    of value
                      | Symbol      of string
                      | Funcall     of expression * expression
                      | Conditional of expression * expression * expression
                      | While_loop  of expression * expression
                      | Sequence    of expression list
    

And I'm pretty much done. Now in C++:

    
    
      --------------------------------------------------------------------------------
      #ifndef __Expression_h__
      #define __Expression_h__
      
      #include <cstdint>
      #include <string>
      #include "Value.h"
      
      
      namespace Script {
      
      class Expression;
      
      class Expression {
      public:
          enum Tag {
              litteral,
              symbol,
              funcall,
              conditional,
              while_loop,
              sequence
          };
      
          union Val {
              Value                   *litteral;
              std::string             *symbol; // or a true symbol?
              std::vector<Expression> *composite;
          };
      
          Expression(const Value&);
          Expression(const std::string&);
          Expression(Tag, std::vector<Expression>*); // takes ownership
          ~Expression();
      
      private:
          Tag _tag;
          Val _val;
      };
      
      } // namespace Script
      
      #endif // __Expression_h__
      --------------------------------------------------------------------------------
    

Don't forget the cpp file either:

    
    
      --------------------------------------------------------------------------------
      #include "Expression.h"
      #include <cstdio>
    
      using namespace Script;
      
      Expression::Expression(const Value& val)
          : _tag(litteral)
      {
          _val.litteral = new Value(val);
      }
      
      Expression::Expression(const std::string& sym)
          : _tag(symbol)
      {
          _val.symbol = new std::string(sym);
      }
      
      Expression::Expression(Tag tag, std::vector<Expression>* exprs)
      {
          if ((tag == funcall     && exprs->size() == 2) ||
              (tag == conditional && exprs->size() == 3) ||
              (tag == while_loop  && exprs->size() == 2) ||
              tag == sequence) {
              _tag = tag;
              _val.composite = exprs;
          } else {
              std::fprintf(stderr, "Expression constructor: Invalid Expression\n");
              exit(1);
          }
      }
      
      Expression::~Expression()
      {
          switch (_tag) {
          case litteral   :
              delete _val.litteral;
              break;
          case symbol     :
              delete _val.symbol;
              break;
          case funcall    :
          case conditional:
          case while_loop :
          case sequence  :
              delete _val.composite;
              break;
          default:
              std::fprintf(stderr, "Expression destructor: broken class invariant\n");
              exit(1);
          }
      }
      --------------------------------------------------------------------------------
    

I may use smart pointers instead of doing my own RAII by hand, but that's
still a hassle. Some may point out that my ugly unsafe union type is not the
way to to this, I should use a class hierarchy and polymorphism. But just
imagine the sheer amount of code I'd have to write.

C++ is a low level language. It's high level pretense is nothing but a thin
veneer that cracks under the slightest scratch. Or, someone show me how to
implement an abstract syntax tree in less than 20 lines of code. I'm lenient:
Haskell and ML only need 6.

(Yes, I'm using Sum types, a feature that's pretty much unique to ML
languages. But no, that's not cheating: providing enumeration and unions but
somehow failing to combine them into sum types is a serious oversight.)

~~~
userbinator
I think you're deliberately making it more verbose than it needs to be. The
class definition could be condensed into:

    
    
        class Expression {
          enum Tag { litteral, symbol, funcall, conditional,
           while_loop, sequence } _tag;
          union {
           Value *litteral;
           std::string *symbol; // or a true symbol?
           std::vector<Expression> *composite;
          } _val;
        };
    

And you could probably use templates or macros to autogenerate most of those
constructors/destructors automatically.

~~~
loup-vaillant
> _I think you 're deliberately making it more verbose than it needs to be._

I swear I am not. This is will be production code, for which I earn my salary.
Your code is terser, but still fundamentally the same as mine. It's still
unsafe (we could access the wrong union member), and it still has to work
around incomplete definitions and the lack of trivial constructors (I wouldn't
use pointers otherwise).

Automating my constructors and destructors would be amazing. Unfortunately, I
don't know how to do it —not without writing over a hundred lines of cryptic
boilerplate first.

------
bschwindHN
So don't use it? These "Why X Sucks" posts mostly seem like clickbait rants an
author writes when they have a frustrating programming day. C++ is a huge
language used all over the place, it's been here awhile, its pitfalls and
warts are known, it can be cumbersome to write, but it's fast and there are a
huge number of quality libraries for it. It's hard to write in. We know. Use
it where it makes sense, use something else where it doesn't.

If you want native code with fast speed and a nice development environment,
give Rust a try if you haven't already.

~~~
anta40
>> give Rust a try

Or Pascal. Combined with Lazarus, we have a nice open source Delphi-like
environment. Really cool, eh?

Rust might be an option for C++ folks who likes functional programming :D

------
nice_byte
Regarding using 3rd party libraries: you don't simply "reference a library".
You include their source code into your project, and compile them together.

Ideally, both your project and the referenced library should be using CMake,
and the library's CMake file should be referenced from your project's CMake
file. If the library doesn't use CMake, you write a CMake file for it.

This is the only approach that worked well for me on all platforms. So, save
yourself the trouble and just use CMake. Yes, I know it has a horrible
language, but it's like the PHP of build systems: it works and lots of
existing libraries use it, making it easier to use them in your own project.

~~~
rdtsc
Yap pretty much. I used C++ for a while then switched to C and Python and
other languages for a decade then had to do some C++ for a bit again. And I
was desperately trying to properly reference and link against some libraries.
And then finally just dropped the source tree in my project and everything
worked. It felt so dirty.

~~~
helmut_hed
Git submodules work pretty great for this IMO. Rather than incorporate a
snapshot of the source, pick a commit hash. Still frozen at a point in time,
but you get to move which one you're using (or point to your own fork!)
whenever you like.

------
_yosefk
> I had an array of widgets. Those widgets had textures. Those textures were
> copied over and over and over again, because containers can do that, so I
> had to go back to rethinking the storage class for the widgets.

Actually, he didn't _have_ to rethink it, and many people don't - instead,
their code just copies things. Avoiding copying increases the chance for
mishandling ownership and deleting a still-used object (or you can use
shared_ptr, an then at some point the reference counting involved might get
slower than the overhead of gc.) Beating gc in terms of memory footprint and
speed without adding bugs is possible, but not necessarily trivial - and it's
often very easy to lose to gc instead.

There are many good reasons why no language ever copied C++'s approach to
"values" and "references", where every type can be passed either by value or
by reference and redefine copying, assignment and now "move semantics." The
proliferation of unnecessary copying is one of those reasons.

~~~
72deluxe
Perhaps he should have put the textures in a central container and have the
widgets use a reference to the texture item?

I would think that adding textures as a child of the widgets would imply that
he WANTED the textures copying. I wouldn't put child items into an object
unless I wanted them copying too, as their lifetime is tied up with their
parent object. The problem is not containers - it is more with his design and
him wanting to control the lifetimes of child textures.

~~~
_yosefk
Well, define "problem." Naive, correct C++ code will copy objects because it's
the simplest way to make sure each object has one obvious owner and won't leak
without having to write memory management code or fiddling with smart
pointers, which have non-trivial semantics. Yeah, you can avoid the copying,
but C++ definitely encourages it in the sense of making it the path of the
least resistance.

------
baldajan
I think the failings in this article stems from a misunderstanding on how to
use C++ correctly, and just compares it to a language the author is more
familiar with, C#. C++ most definitely has a lot of faults, but at the same
time, I've seen and worked with some truly awesome code bases using C++. And
the above statement can be used for nearly every language that rapidly evolves
(C++ pre 2011 was... well, a pain in the a __to use).

All in all, I do wish these articles wouldn't make it to the front page of HN,
because they don't really add much value to the community, but simply acts as
a negative rant, not adding anything constructive.

~~~
alkonaut
> All in all, I do wish these articles wouldn't make it to the front page of
> HN, because they don't really add much value to the community

In my opinion the positive value provided by [legacy tool X is really bad] is
if you read it like [X is being used not for technical merit but just because
of momentum and the fact that we have grown comfortable with it and we really
should be adopting alternatives Y or Z at a faster rate than we do]. Titles of
articles are often "X is bad" or "X considered harmful" or some other
inflammatory clickbait title. That's unfortunate, but it's how the web works.

If just a handful of people read these posts, nod, and then take a look at
Rust (for example) then that's value. Yesterday X was git, on saturday X was
glibc, today X is C++ and so on.

~~~
RotsiserMho
I think the discussion such an article generates has value. I've learned about
some nice C++ tools in this thread that I may not have otherwise.

------
cheez
As a C++ dev for 10+ years, I wanted to hate this article and say it was all
wrong but a lot of what makes me efficient with C++ now is avoiding the
problems that the article publicizes.

However, I do believe that every language has its own problems at least as
severe as C++.

------
fizixer
In support, I would mention the following:

[1] Mike Acton's talk:
[https://www.youtube.com/watch?v=rX0ItVEVjHc](https://www.youtube.com/watch?v=rX0ItVEVjHc)

[2] ZeroMQ article: [http://250bpm.com/blog:4](http://250bpm.com/blog:4)

[3] Cat-V harmful page:
[http://harmful.cat-v.org/software/c++/](http://harmful.cat-v.org/software/c++/)

------
antiquark
Yeah C++ is annoying at the beginning... but just dedicate yourself for 10-15
years, it'll become a piece of cake!

~~~
fizixer
Yeah right, and after 10-15 years you'll be able to perform tasks without a
problem that a 2-year experienced programmer can perform in a scripting
language if (s)he wants to be expressive, or C if (s)he wants to achieve
performance.

"Clever solutions give rise to artificial problems that can require even more
cleverness to solve".

Not to mention the mad scientists sitting in ISO conference rooms constantly
thinking "how can we top our previous clevernesses?". So good luck with the
language being the same in 10-15 years.

~~~
blub
These kinds of ridiculous statements poison the discussion and make it devolve
into a complete mess. Stop that!

1) C is very difficult to use correctly even with the best guidelines and
intentions. My best bet for avoiding memory errors is being super-careful
(read: super-slow) AND using static analysis AND using Valgrind to check
afterwards. The last two steps are mandatory.

Contrast this with C++, where just by using smart pointers, vector and array I
can eliminate a whole bunch of typical C errors.

2) Scripting languages solve different problems than C++. The typical C++
tasks can't be performed by your programmer with 2 years of experience no more
than they could by the same programmer if they had 40 years of experience.

~~~
ArkyBeagle
Static analysis and Valgrind are wonderful.

This being said, I think I was six months into using 'C' when I mostly stopped
having memory errors. Mainly, you construct the operations against memory
objects based on building up series of constraints. This is less trouble than
it sounds.

You learn to conform to the expectations of the language and libraries. And
you use less of 'C' than there is to use. And when things get past a certain
level of complexity, I tend towards making them state machines.

Should you have to do that? I have no idea. I do agree that based on most
other people's 'C' code, it does appear to be painful for a great many people.

~~~
blub
Do you have some example? I can't really picture the series of constraints
that you mentioned...

~~~
ArkyBeagle
RAII type things are part of it. The rest is simply making sure all the
constraints are met. The fewer operational constraints, the better.

For text I/O parsing, just be semi formal about it at least. Check your
indices, be careful of integer overflow and be judicious in the use of
floating point. Use block I/O instead of the finer-grained things in stdio.h .

Have instrumentation built in that you can enable to capture test vectors ( if
you have the resources ). Error counters can tell you a lot.

the mechanism of choice for managing complexity tends towards state machines
and sometimes message passing.

That's a start.

------
userbinator
This is more of a "why C++ programmers suck", but the main gripe I have is
with programmers who seem to be obsessed with stuffing as much of the latest
C++20 (or whatever they're at now) features as possible into the code they
write, making it more verbose and bloated than necessary. The fact that these
features now exist, somehow makes people want to find a use for them. The same
phenomenon doesn't happen with C because the language is so much simpler.

 _and today the first thing I suggest to people is to stop thinking that C++
is a superset of C_

I think that's the problem. It's certainly possible to use its features
sparingly, as an object-oriented superset of C, resulting in the code as
performant as C but less verbose, which is IMHO the main attraction of the
language. Going crazy with the abstraction is what turns it into a mess.
(Compare the similar "use as much as possible, and maybe more" behaviour often
encountered in the past with design patterns, and the huge OOP-ifying of
everything when OOP just started becoming popular. Maybe in a few years C++
will settle down with most code being written in a saner subset, with only
sparing use of the advanced stuff...)

~~~
72deluxe
I thought that the latest C++11-onwards additions made code less verbose
because I don't have to write so much code as the STL has a LOT more in it?
And don't have to write so many explicit constructors, destructors, move
operators, assignment operators etc.?

The code is much simpler when I look at my C++11 code compared to C++03.

------
melted
On a more serious note, just take the Google coding style and strike out
everything it says about exceptions. Boom! A relatively painless C++. You
don't have to use every trick in the book.

------
pcunite
As a long time C++ programmer C# felt ... it felt good. Yeah, the memory and
the non-native binaries make it a non-starter for most things I do. But wow, I
loved it.

~~~
Gibbon1
In the early nineties I found myself faced with spending a year learning to
program in C++ with Microsoft foundation classes or giving up on Windows
programming. After ten years started sh*tcoding in C#. I feel like I missed
out on a lot of pointless suffering.

~~~
zerr
Yes, Win32 API/MFC was a frustration, but then I've discovered Delphi/VCL. I
never liked Pascal so I was really happy I've found about Borland C++ Builder.
I did some N-tier apps with it, it was a pleasure to work.

~~~
72deluxe
Didn't Borland suffer a massive brain-drain and all the developers left after
the C++ Architect mismanagement? The VCL is full of bugs isn't it? And suffers
horrible redraw and flicker the last time I used it (years and years ago!)

------
smilekzs
Quoting author's comments:

> If the Modules standard is adopted, half of the issues are gone, I think.

Agreed. Had there been a sane module system + package/dependency manager +
CLI/build tool like almost every "modern" language does, C++ would be much,
much more usable.

------
Ace17
"The split between source and headers, which makes project management quite
slow. If you make all header libraries you’ll have a lot of copied code – the
binaries will be larger. You’ll have to recompile that code every time you
want to use it."

You can't say "the split between source and header sucks" just because it's
painfull to use it wrong ("all header libraries") !

(All header libraries are justified when you're dealing with highly templated
stuff, but in this case you have no way to avoid recompiling this code every
time you use it, as each required template instance needs to be generated
anyway - smart compilers will get rid of duplicated instanciations).

The split between source and headers is a key to good encapsulation. From a
software design point of view, it's good way to break long dependency chains.

~~~
Too
Spoken like a true c++ fanatic. Good encapsulation does not require splitting
things up in different files that are later conditionally merged back together
by a dumb non language aware text pre processor. Other languages manages this
fine without it. And "Template instantiation"? Thats an implementation detail
I don't want to think about.

C++ does have its nice parts and it does have its uses but some parts truly
are shit, get out of the Stockholm syndrome and admit it.

~~~
Ace17
No need to be rude!

Let's get this straight: I'm not advocating for the preprocessor here. I will
happily put it in the trashbin where it belongs as soon as I have support for
modules in C++ (By the way, 90% of the code I write is written in the D
programming language, which has modules, and no preprocessor).

I'm advocating for interface files.

Whatever mechanism you use, you still need a way to separate interface files
from implementation files. Interface files can be header files, they can be
java files containing a single java 'interface', they can be "D interface"
files (.di). It doesn't matter which mechanism you use for this, as long as
you have a way for your caller not to depend on the implementation of callee
(which might, for example, directly depend on a specific audio API, for
example).

My point is, if you want the caller to be properly isolated from the
implementation of the callee, having to maintain signatures in an interface
file is unavoidable.

------
lossolo
I hope he is better in C++ than creating frontend for websites.

------
melted
Site is clearly not served with C++. :-)

~~~
dorinlazar
Yes, and that's a pity. And I will fix that as soon as I get my hands on it -
I never knew that I needed to write that web backend myself. This site proved
me wrong :D

~~~
melted
Even just reverse proxy in front (written in C++, naturally) would have
probably saved the situation.

------
claudius
Not sure what to make of this.

Specifically:

× There is quite absolutely no need for some fancypants IDE. Use a text editor
that can indent stuff automatically and maybe has some syntax highlighting and
you’re good to go and write all the code you want. Yes, even C++!

× The split between header files and translation units is ugly, especially if
part of your class can be in a translation unit and part of it is templated
and must be in a header file. But if your class is all-header, you just have a
single file (which may be compiled into more than one block of code for
templates); if your class is not templated, you just have a nice little header
with your comments and the implementation hidden away. Yes, you may need to
add a new field to both your header and your constructor implementation if you
want it to be different in different constructor calls, but that’s hardly
avoidable?!

× The C preprocessor might be ugly sometimes. Don’t use it if you think that.
Everything will be fine. You’ll be okay.

× Namespaces are extremely useful to separate different sets of functions and
classes. I find std::vector and boost::program_options::options much more
readable than StdVector and BoostProgramOptionsOption. There’s only so many
letters in the alphabet, names will need to be long eventually. If you really
don’t like namespaces, just use using generously.

× Portability is fine between decent compilers on decent operating systems.
Yes, Microsofts Visual Studio sucked big time for a long time and if you want
to use a Unix-native compiler on a weird platform, things might be strange.
But I haven’t seen a Unix yet where I couldn’t compile my code.

× Not sure what to make of the next paragraph, are they just complaining that
they can’t keep a mental model of some header files in their mind and that
this must absolutely be the fault of the language?

× I don’t get the issue with std::chrono::duration. The reference is clear,
the code is not too horrible and the C# code isn’t even better?

× Hint: \n does exactly what you want.

× push_back() and emplace_back() are two very different things and I’m glad
that they’re different functions, as that makes it very clear whether you’re
copying stuff around or constructing it in-place.

× The (few) bits of the boost library that I used so far were amazingly well
documented. Yes, if you want to dig a little deeper, you may have to read some
not-so-easy to understand code, but have you seen the code that powers your
lovely C# runtime? Do you think it would be substantially easier to
understand?

~~~
gpderetta
I'm exclusively an emacs user, but I would definitely like better IDE
functionality. I use the builtin fast jump-to-file and text based
autocompletion, plus SilverSearcher powered text search and it is fine 90% of
the time.

Still I would love to have working jump to definition/declaration/reference,
type and context exact autocompletion, semantic based highlighting and on-the-
fly error checking. I do not care much for refactoring support except maybe
basic renaming help.

There is EDE, but in my experience it fails very quickly on anything beyond
trivial projects. There are a few clang based indexing/autocompletion engines
(I favor rtags) which can do all of the above amazingly well, but they are not
impressively fast and in my experience any setup I tried bitrots extremely
quickly.

~~~
dman
Use rtags. Its great.

------
moron4hire
C++ is very, very hurt by not having a base Object type from which all other
types derive. Because of this, we get templates, and templates suck a lot.

Generics in Java are even worse. All of the idiocy of C++ templates + Java
type-erased containers, none of the benefits. I've been bit way too many times
by Java generics just forgetting what type they contain.

Generics in C# are slightly better, especially in that there are a lot of
different types of constraints you can apply to them. When applied
judiciously, they can greatly simplify a lot of code. They are work best when
everything is specified "correctly" with interfaces. Hold on a sec...

Sometimes I think templates/generics is all just a hack to get around the fact
that I can't add interfaces to types I didn't define myself. When I'm
designing a wholly closed system, I'm often going the old-old Java way of
explicit interfaces for everything. It just keeps you honest about state
encapsulation, which then keeps you honest about state transitions, which then
basically just makes the program write itself.

So if you have a system like that, C# generics and its constraints work
_really_ well. But probably the entire reason you wanted generics in the first
place was to not have to write all those interfaces. And you still can't add
interfaces to things that you didn't write.

But at least you can write extension methods for them.

Of course, you can't get all the way to an algebraic type system with it. It
makes you think you can. But you can't. That hurts.

~~~
nly
> Sometimes I think templates/generics is all just a hack to get around the
> fact that I can't add interfaces to types I didn't define myself

You can though. They're called free functions. Types should only expose their
basis functions[0] as members, keeping their surface small. Once you have that
small set of reasonable functions, you can write free functions to do
everything else. Sometimes if several of your operand types share a minimal
set of basis functions it's useful to make these algorithms templates. That's
all.

Scott Meyers was writing about this stuff 20 years ago. Here's a 15 year old
example[1]. Here's another, more recent, article[1] by Walter Bright, which
compares the approaches of C#, C++ and D.

This is the reason why C++ has the 'madness', as some people see it, of
function overloading and Argument Dependent Lookup[3] and, soon, a Unified
Call Syntax of its own.

So you want all classes derived from an Object base. Fine. What are you basis
functions for Object?

[0]
[https://en.wikipedia.org/wiki/Basis_function](https://en.wikipedia.org/wiki/Basis_function)

[1] [http://www.drdobbs.com/cpp/how-non-member-functions-
improve-...](http://www.drdobbs.com/cpp/how-non-member-functions-improve-
encapsu/184401197?pgno=3)

[2] [http://www.drdobbs.com/cpp/uniform-function-call-
syntax/2327...](http://www.drdobbs.com/cpp/uniform-function-call-
syntax/232700394)

[3]
[http://en.cppreference.com/w/cpp/language/adl](http://en.cppreference.com/w/cpp/language/adl)

------
fenesiistvan
What about Embarcadero C++ Builder (old Borland)?
[http://www.embarcadero.com/products/cbuilder](http://www.embarcadero.com/products/cbuilder)

It has a very good IDE.

Easy to add external libraries.

You don't need to use the ugly STL because it comes with it's helper classes
for almost everything (the VCL library).

Nobody using it?

~~~
PeCaN
I use it for a living, and I cannot recommend that piece of shit.

The IDE is alright, except the IntelliSense, if you can even call it that,
becomes unusably slow in sufficiently large (really, just non-trivial)
projects. The 32-bit compiler mostly supports C++98, with a couple C++11
features and a few missing C++98 ones. Don't expect to be able to use many
open-source C++ libraries. The 64-bit compiler is a fork of an older version
of clang, so you get more C++11 support but some of the Embarcadero extensions
are missing (yeah, code isn't even _syntactically_ portable between 32-bit and
64-bit C++Builder).

The compiler ICEs if you look at it funny and the general solution to fixing a
build problem is to restart the IDE. If you have a syntax error, you can
basically guarantee that it won't report the correct error location (usually
it'll give you some system header files).

The debugger is nice enough (it's basically a really shitty reimplementation
of 1/10th of GDB, with a more-or-less functional GUI slapped on top) until it
crashes, which thankfully is much rarer than the compiler.

Using external libraries is easy enough as long as they're packaged as
C++Builder or Delphi components. Unless, of course, you manage to fuck up the
install process (quite easy) in which case you'll be editing a few registry
keys (yup). If you're trying to use a regular C++ library—assuming, of course,
that it sticks to C++98 features and doesn't use SFINAE—then you usually only
have to edit the library's code a bit to work around C++Builder's quirks and
you're set. Oh yeah, and you can't use C libraries built with MinGW
(C++Builder uses its own object file format), which means you're stuck with
C89 (and a little bit of C99).

VCL makes the STL look positively dazzling. Templates were inconsistently
bolted onto the VCL, so usually you've got TObject* pointers and casting. VCL
objects can't be stack allocated, because... reasons? VCL's memory management
is extremely unclear, but it's mostly reference counted (explains the heap-
only restriction)... probably.

There's a reason nobody's using it. It's a fucking piece of trash that needs
to die already.

/rant

At least there's been enough outcry at my workplace that we're switching to C#
for the next project.

~~~
blub
Such a shame. Borland couldn't compete with MS (partly due to some dirty
tricks MS used) and they've been on a downward course for a long time - they
sold their developer tools divison a long time ago.

C++ Builder was the C++ version of Delphi, a major productivity booster for
Windows development. I remember using version 1.0 - it was truly amazing how
fast one could develop UI applications with it. I would say it was about as
easy as using Xcode's interface builder, when the competition was basically
coding MFC classes (or WinAPI!) by hand. It had database bindings and one
could link controls with data sources in a WYSIWYG interface in the time it
took to put a button on the screen with MFC.

However, it was expensive and the compiler was not as good as MS's. I never
had the chance to use it profesionally, everyone was using Visual C++. As the
years passed I forgot about Borland...

Luckily the legacy of rapid application development lives on in Qt: it's open-
source, cross-platform, with a strong community and uses modern C++ tooling.

~~~
72deluxe
wxWidgets is also good as an alternative to Qt, but with a smaller community.
I use it and don't have any problems with it (a few bugs in the wxAui classes
though).

I think everyone left Borland after their C++ Architect project was binned,
the Kylix attempt ("building font metrics..."), they changed their name and
core idea, and the Delphi language designer was head-hunted to design C# for
Microsoft (unless I am mistaken??).

They released a PHP editor but I can't see them selling much of that.

------
gpderetta
> Notice the “unreadable code” from C#, even the portability issue (hint: \n
> does not always do what you think it does).

No, it does exactly what you think it does (unless it is a binary stream), it
adds an end-of-line to the stream. If the underlying platform needs a "\r\n",
the stream will do the conversion.

~~~
dorinlazar
Yes and no. std::endl is not an alias for '\n', for good reason.

------
pjmlp
I still love C++, in spite of its C underpinnings that make writing safe code
an almost impossible task in large teams, unless one controls what everyone is
doing.

However, whenever I see SFINAE mixed with type traits, decltypes and arrow
return declarations, I am not sure if I still love it that much.

------
Murk
A lot of people insist on avoiding the use of "using namepspace x" in .cpp
files. This makes no sense to me, it makes things a lot easier to read. It
never seems to cause a problem, and it's trivially fixed if a conflict shows
up due to a header change later.

~~~
jcelerier
> It never seems to cause a problem

It does if you want to use unity builds at some point down the road. For my
app it took the build time from 25 minutes to 2 - 3 minutes which is critical
when doing CI on a lot of operating systems and with a big build matrix.

~~~
Murk
I am not familiar with unity, but why should it slow down builds?

~~~
lfowles
From a quick google, unity builds are akin to #include-ing every file in the
project (yes, the .cpp files too).

------
ksk
Contrarian opinions can be useful and valuable. However I don't see much
substance in this article. Could someone list what this person has done to
make their opinion worth something?

~~~
dorinlazar
I can confirm that absolutely nothing of import. I think that the attention
shown to my rant is overblown, although I do enjoy the good points made by a
lot of commentators here.

------
72deluxe
I do not see how his example of STL vs LINQ is hard to read. I think this
article is just a rant.

------
hathym
Then try writing an operating system in C# (or any fun language) and we can
talk later which language sucks. C++ is an awesome tool when used for the
right job.

~~~
dalailambda
I feel like this is a bad argument to be making. If a language's "level of
suck" were based on its ability to write operating systems, then the massive
boost in programmer productivity we see today from languages which sought to
depart from that domain wouldn't exist. Tangential to that, I consider Rust a
"fun" language compared to C++, and it is definitely capable of doing anything
C++ can do[1].

By the way, Midori[2] was written in C#. Granted it had its own AOT compiler
and started to diverge into a different language, but nevertheless, it was C#.
I'd suggest looking through Joe Duffy's blog posts[3] as he explains it better
than I could.

[1] [https://github.com/redox-os/redox](https://github.com/redox-os/redox) [2]
[https://en.wikipedia.org/wiki/Midori_(operating_system)](https://en.wikipedia.org/wiki/Midori_\(operating_system\))
[3] [http://joeduffyblog.com/2015/12/19/safe-native-
code/](http://joeduffyblog.com/2015/12/19/safe-native-code/)

------
hellofunk
>I suggest to people is to stop thinking that C++ is a superset of C. It is,
but let’s forget that.

Hard to take any article seriously that makes such a glaring and naive point.
C++ is not a superset of C and if the author really knew the language well, he
would not make this point.

~~~
dorinlazar
In my post I suggested to watch a presentation. Watch it, you'll understand
what Kate Gregory argues, and I completely agree with her point of view.

~~~
hellofunk
I will watch it, thanks. But that won't change the fact that C++ is not at all
a superset of the C language, they are genuinely different languages.
Objective-C however _is_ technically a strict superset of C. All C code runs
as expected in Objective-C. This is not true in C++ where the same C code
might compile and produce different output when run in a C++ context, or that
several C idioms are not possible in C++.

------
marvel_boy
"What does the 11 from C++11 mean? The number of feet they glued to the
octopus to make it a better." This

