
Talking to C Programmers about C++ [video] - adamnemecek
https://www.youtube.com/watch?v=D7Sd8A6_fYU
======
wott
After 20 minutes spent complaining that nobody listens to him, several minutes
of diversion to come to the point that people are not rational because they
favour world view and moral sense (characteristics that he calls 'emotional')
compared to self-interest, and that he finds that dismaying.

Well, I am dismayed that one may consider prioritising selfishness and
immediate interest as rational and prioritising global thinking as emotional,
and not the opposite. And that is supposed to serve as an anchor to the
following points. Well...

Now at 30 minutes and the subject of the talk was barely tackled. I am not
sure I have the strength to inflict myself the remaining hour.

~~~
bischofs
It seems like the minutia and subtlety of many c++ features at the cost of
simplicity and readability lend themselves to cocky, in-love-with-themselves
developers like this guy (who tells us upfront he wasn't actually building
anything embedded in c++?!).

------
gravypod
The problem with C++ is the constant introduction of unneeded features that
are infinity obscure in necessity.

People will say "Oh just don't use that feature" but that's not how this
works. If something is there it is used. In reference to C, I don't think I
know of a single feature or release that had major changes in how I wrote C.
Maybe C99 and allowing me to declare in a for loop.

I've been using C++ for class this semester and the only thing I like is
reference types. Makes pointers much more concise. Other then that it can all
go in the bin. In order to keep my C++ project clean I've needed to avoid a
huge set of features and keep it in a data-oriented design.

~~~
jonstewart
The problem with posts about C++ on Hacker News is that people who aren't
experienced C++ programmers (you've been using C++ for a semester? do tell)
feel compelled to write posts explaining the problems with C++.

~~~
_yosefk
As someone who's had to deal with C++ since the last century, I find that one
problem with C++ is that people who aren't experienced C++ programmers can't
get shit done, especially in a code base where experienced C++ programmers
have demonstrated their erudition and knowledge of C++ arcana in all its
glory. In fact, the intersection of people who had the patience to learn
enough C++ to get shit done and people who also have the patience or basic
desire to _actually_ get shit done (as opposed to programming wanky wrappers
and stuff) is annoyingly small (this however is not true everywhere, I'd
expect no such problem to exist with game programmers, for example.)

The fact that a language is terrible for newcomers is a real problem, and a
newcomer is a very good judge of that even if they aren't a very good judge of
other aspects.

Especially loathsome are those people who teach, say, undergraduates majoring
in physics some C++ as a way to introduce them to programming. You might think
that someone who manages to deal with the math needed to do physics would be
able to absorb C++, and often you'd think wrong; one physics undergrad told an
experienced programmer after trying to understand what the fuck cout<<x
actually does, "your head is full of garbage!", by which he meant that the
amount of completely arbitrary rules that you need to memorize was not
something that dealing with math and science prepared him for.

From the above I conclude that people who have a semester's worth of
experience in C++ might not be C++ experts but they certainly know enough to
burn the instructor who chose C++ in the first place at the stake.

~~~
sseagull
> what the fuck cout<<x actually does

I'm not sure where that conversation would go. It prints to stdout. Would the
student say the same thing about printf("%d", x)? How far down the rabbit hole
did he want to go?

Stream insertion syntax os pretty bad, though, I'll agree with that.
Especially when you want to print floating point.

~~~
gravypod
The conversation then shifts to how it does this? What if I want to print to
something else? Why if I want to read differently from a stream?

When you provide a shorthand that's all well and good but when you TEACH a
short hand it's what's ONLY used by the students.

The students will assume there is no other way to read and write then using >>
and << which is horribly incorrect. These are largely inadequate measures for
reading and writing in my experience as you probably want to do formatting
which printf just does better.

So many of the students in my CS class this semester can't do the first lab,
which in all essence, is a tokenizer because they don't know that there are
other ways for writing to, or reading from, a stream!

A short hand should only be used in a majority if it can do everything the
long hand way can do.

Also for anyone interested what my first C++ project looked like you can see
here:

[https://web.njit.edu/~gwryan/CS280/CS280-Program-1-Fall-2016...](https://web.njit.edu/~gwryan/CS280/CS280-Program-1-Fall-2016-R1.pdf)

[https://git.gravypod.com/gravypod/school/tree/master/cs280/h...](https://git.gravypod.com/gravypod/school/tree/master/cs280/homework/program_1)

It's not my best work, but if any C++ people want to notify me of things I'm
doing that's wrong I'm more then happy to learn.

~~~
sseagull
I will agree with the point that the other methods of reading/writing from
streams aren't taught early enough, and that formatted output is pretty bad
with streams. I've actually written a wrapper around snprintf for printing in
c++ (I should put that on github sometime)

Your project looks good. Two minor observations: 1.) You have 'using'
statements in a header file. This is fine for a small project, but is
considered bad form in larger projects (every file that includes that header
will end up including the 'using' statements. This can cause collisions in
large projects).

2.) Const correctness is a good habit to get into. (Ie, only pass non-const
references if you are actually changing the object in the function)

~~~
gravypod
I wasn't sure how const worked in this language so I decided not to mess with
it yet.

Coming from Java I have a blanket policy that every variable is final unless
needed to be modified. I've run into those pain points.

Your first observation is one I have some into as well but I haven't been
taught how to do this.

For example if my header file needs to define the method:

    
    
       void test(std::string something);
    

Is it bad form to them define the header in my cpp file as such?

    
    
       void test(string something);
    

Isn't that also bad form? Coming from C some things like this _could_ be done
but very much shouldn't have been done.

I know for a fact that namespacing is one of the hugest benifits to large
projects I just don't know how to use the tools provided by C++ to do it
correctly. Java? Yea I can get anything you want nice and tucked away. But C++
with the way headers and namespacing works its difficult to obviously see what
I want to do and how to get it done.

Any examples?

~~~
jonstewart
I'm not sure I understand the question completely. Do you mean "declare"
instead of "define" in "if my header file needs to define the method"? Or are
you asking about declaring the parameter to test as "std::string" in the
header but then only as "string" in the .cpp definition, because of the
presence of a using statement?

------
partycoder
C++ is really hard. I have learned enough about it to understand that there's
a lot of idiomatic ways of achieving things that I do not understand,
especially with the latest standards.

When someone claims to know C++, especially in a recruitment context, I tend
to challenge that, since it's really hard to actually believe these days. Some
people claim to know C++, but basically just write everything as if it was C.

~~~
TickleSteve
C++ is not _one_ language... there are many styles, for example:

\- 'C with objects'.

\- 'Everything is a template'.

\- 'Embedded C++' (its a real standard, google it).

\- functional.

\- 'modern'.

(thats not a complete list either).

Each one of those is technically the same language, but they're all using a
different subset of features and are almost unrecognisable from the rest.

~~~
partycoder
It is one language. Many of those subsets are not mutually exclusive.

Regardless of what your preference is, if you claim to know C++ you need to at
least know some of its basic features, such as references, streams, templates,
STL, etc. (features that have been around for a long time).

And if you claim expertise, to at least be familiar with basic features from
the new standards.

~~~
TickleSteve
true, they're all overlapping subsets....

The point being that the way you structure your software in each of those
styles is very, very different.

They're all idiomatic C++.... just different idioms.

In fact, thinking about it, thats what it is...

C++ is a multi-idiom language.

~~~
ratboy666
Sure, with an execution model that is so complex that it takes scientific
experimentation to determine the /best/ (in terms of execution speed) to write
code to manipulate a simple memory mapped device. (This, from the lecture).

That is so complex, it is the only language that I need the language at hand
to read someone else's code. Not a library reference, a /language/ reference.

Indeed, I am maintaing one C++ application. This is a wrapper for CEF3
([https://cefbuilds.com/](https://cefbuilds.com/)). This is the Chromium
browser as a library. I have to support the library and wrapper on two
platforms: Linux 64 bit and Windows 64 bit. Note that the usual Windows build
uses the Microsoft C++ compiler. But, I am uses mingw. This requires source
code edits to compile! I blame the complexity of the language.

Indeed, C++ is so difficult that the shop I work for (which is, by the nature
of our product, very conservative) has gone to Java instead.

~~~
pjmlp
We did the same in 2006, and are mainly a Java/.NET consulting shop nowadays,
but I still use C++ on side projects.

Given language difficulty, while I hope never to maintain C++ code that makes
use of SFINAE, Java's simplicity is misleading.

The language might appear simple, but mastering the whole Java eco-system
(JSE, JEE, Spring, embedded, Android, features per JDK version), performance
monitoring tools, commercial JDKs and IDEs, isn't that easier either.

~~~
satysin
There is nothing "simple" about Java once you get past the basics. When you
get into the EE world it gets extremely complicated.

~~~
qwertyuiop924
No.

There's _everything_ simple about Java. The semantics of Java are actually
pretty simple, at least compared to C++. What's complicated are the
monstrosities people build with Java, but those aren't inherent in the
language.

Saying that Java is complicated because EE exists is like saying that C is
complicated because Linux exists: Complexity can be built atop simplicity. And
for some reason, Java is a complexity magnet.

~~~
MereInterest
I would say that the complexity of a language and the complexity of programs
within that language are inversely correlated. Java is a very simple language,
but as a result, the programs written in it must be more complicated to make
up for the shortcomings of the language.

As an example, Java's lifetime rules are much simpler than those of C++. At
some point after all references are gone, the object will be garbage
collected. Simple. But as a result of this simplicity, you don't know when the
finalizer will be called. You can't use it, for example, to flush and close a
file, because you don't know when file will be closed. Instead, you need to
use try/except/finally, and so you can't add this to an existing class,
because it would require code modification from all the users of the class.

Up until Java 8 and lambda functions, functions could not be passed as
arguments to other functions. Therefore, the developer needed to make an
entirely new classes derived from "Callable". Complexity that came from the
simplicity of the language.

C++ has a lot of complexity in the language itself. I won't deny that. What I
will argue is that the complexity of the language enables simplicity in
programs.

Edit: Lambda statements came in Java 8, not Java 7.

~~~
qwertyuiop924
No, not really. Complexity is not about the language: It's about how you use
it. It's not necessarily Java's featureset that makes it so complex, it's its
idioms.

C++'s lifetime rules, on most variables, are this: It's allocated until you
say it isn't. Some of the vars might be refcounted or GCed, but with GC you've
still got the same problem on your hands as finalizers, and refcounting can't
handle cycles. Manual memory management is dramatically more error-prone than
finalizers ever were (unless you're using RAII, but that's not entirely
idiomatic, and cannot be).

As for functions not being able to be passed as args, that's not simplicity,
that's a straight up limitation. What makes a language simple is uniformity,
simplicity, and consistency. Java has a good deal more of all of these than
C++

Complexity in the language doesn't enable simplicity in programs, though,
because now your program has to deal with 6000 different special cases.

In any case, Lisp and Scheme are possibly the simplest languages, and are
celebrated for their power, clarity, and the simplicity with which they can
express programs.

~~~
MereInterest
I'd be interested to hear why you say that RAII cannot be idiomatic. With
`std::unique_ptr` and `std::shared_ptr` for handling pointers, `std::vector`
for handling data arrays, `std::string` for handling char arrays, I would
argue that modern C++ is very heavily RAII. At this point, if I have a class
that cannot be declared on the stack, with cleanup handled by RAII, I consider
it to be a broken class.

Good point on limitations vs simplicity. I think that there are different
forms of complexity. Some complexity is necessary, due to the nature of the
underlying problem. Other complexity is incidental, being due to poor
implementations. As an example of essential complexity, C++ has different
declarations for stack-based variables and heap-based variables, while Java
does not. This is because Java does not allow classes to be declared on the
heap, and so it does not need an extra form of declaration. On the other hand,
C++ definitely has lots of incidental complexity as well, mostly due to its
long history. Having four different constructs for loops is incidental
complexity.

I agree that the idioms are what make Java programs be complicated, rather
than the language itself. What I'm not sure on is how much those idioms are
needed to overcome limitations in the language, and how much they are
unnecessary parts of the culture.

Oh, absolutely on Lisp. Lisp/Scheme are amazingly simple, and amazingly
powerful. The one downside that I've found is that it doesn't correspond to
the hardware as much. Much of C++'s complexity stems from trying to provide as
many features as possible while still compiling down to reasonably fast code.

~~~
pjmlp
The main issue with RAII is that you can only do properly if as you say, the
classes were designed to be stack allocated.

Also that no one just placed such class in the the heap, and it was missed,
because no one is actually doing code reviews or making use of static
analysis.

Another issue with best practices and ownership are binary libraries. There
isn't any sort of control one can have over them, so they are the place where
RAII and ownership just goes out of the window.

In any case this is much worse in C than C++, because at least C++ does offer
some language tools to deal with it, however there is no rescue from
developers using C with a C++ compiler.

> Oh, absolutely on Lisp. Lisp/Scheme are amazingly simple, and amazingly
> powerful. The one downside that I've found is that it doesn't correspond to
> the hardware as much.

Actually it can also be an upside, as you see with the adoption of FP patterns
in mainstream languages, including C++.

One of the themes at CppCon was exactly hardware heterogeneity and possible
C++ abstractions to take advantage of it, while keeping the algorithms high
level.

~~~
MereInterest
I feel that the solution to both classes designed for heap allocation and
binary libraries is the same: making a decent wrapper around them that obeys
RAII. In many cases, this is just requires using `unique_ptr` with a custom
deleter.

    
    
        auto deleter = [](unsafe_type* t) { cleanup_unsafe(t); }
        std::unique_ptr<unsafe_type, decltype(deleter)> safe(make_unsafe(), deleter);
    

If this is used in many places, you can make a very easy wrapper class to
handle it.

    
    
        class safe_wrapper {
        public:
          safe_wrapper()
            : unsafe(make_unsafe()) { }
          ~safe_wrapper() {
            cleanup_unsafe();
          }
    
          unsafe_type* operator->() { return unsafe; }
        private:
          unsafe_type* unsafe;
        };
    

(Note that the example there is only for use within a single function. If the
safe_wrapper is to be returned from a function, then the copy/move operators
should be defined as needed.)

Certainly, when passing ownership back to the binary library, you are relying
on it to correctly handle ownership. But so long as the ownership is in one's
own code, you can easily add the type safety.

Regarding a stack-based class being accidentally placed on the heap, you can't
prevent all errors, you can only make it less likely. I'd argue that it is
easier to accidentally forget to call a cleanup function than it is to
accidentally place something on the heap. With C++11 and up, any calls to
"new" should be regarded with deep suspicion.

True on the FP patterns moving in, and I love them. `std::function` is a joy
to work with, especially as compared to either C-style function pointers or
inheritance from a "callable" type.

------
faragon
In my opinion, many C++ projects would be simpler, cheaper, safer, and better
maintained, if were written in C (with adequate libraries, e.g. for strings,
vectors, maps, threads, timers, sockets, etc.).

~~~
sseagull
A vector/map of what? How do I have a map of some key to a custom structure?
How do you do this simply without templates? Separate libraries? Macro hell?

How do you handle types which need to free memory without destructors?
Manually loop over the vector and free stuff every time one goes out of scope?
That doesn't seem safer to me.

~~~
faragon
>>A vector/map of what? How do I have a map of some key to a custom structure?
How do you do this simply without templates? Separate libraries? Macro hell?

Separate libraries, without "macro hell".

>>How do you handle types which need to free memory without destructors?
Manually loop over the vector and free stuff every time one goes out of scope?
That doesn't seem safer to me.

Providing both heap and stack based allocation. E.g. allocating a vector in
the stack would require no explicit de-allocation (example:
[https://github.com/faragon/libsrt](https://github.com/faragon/libsrt)). For
heap allocation, you would need to call some sometype_free(&a) function,
obviously (there is no RAII in C).

~~~
aksx
>For heap allocation, you would need to call some sometype_free(&a) function

i find '__attribute__((cleanup (fn)))' fascinating in C, need to try it in
some production code though.

~~~
pjmlp
That is GCC C, not ANSI C.

------
FrozenVoid
Only a handful of modern C++ features appeal to me. In order to use them, i
actually have to use other features(less desirable, like templates or class
inheritance) which create bloat, latency and corner cases requiring knowledge
of the inner structure of the things(like variadic functions actually being
variadic template syntax sugar). Ease of use which C++ brings is 'balanced' by
opaque and hard debugging, large executable sizes and large memory use.

~~~
KayEss
Can you give some concrete examples?

~~~
FrozenVoid
[http://pastebin.com/fgPhGaxz](http://pastebin.com/fgPhGaxz)

~~~
KayEss
Personally I think that looks pretty good. There's no templates, no
inheritance. Not sure what would make bloat there nor latency. Whatever the
faults of the syntax for folding, it's got to be better than VA_ARGS hasn't
it?

~~~
adsofhoads
There are templates: for example

    
    
        void print1(auto x){std::cout<< x;}
    

is a function template

    
    
        template <class T>
        void print1(T x){std::cout<< x;}
    

This is not valid C++14 however, so it doesn't compile. If you replace these,
you'll probably still get a stack overflow while expanding the templates
because there are almost 7000 arguments to a single function call.

~~~
FrozenVoid
>This is not valid C++14 however, so it doesn't compile.

It is "valid C++" IF there are fewer arguments, like 6-10

The example illustrates C++ internal representation of "variadic functions".

~~~
adsofhoads
I was referring to the use of generic functions (ie. with an argument with
type-specifier auto) which is not C++14. Your copy of g++ may accept it as an
extension.

------
KayEss
Scott Adams (Dilbert) has been writing extensively on persuasion for the last
year or so, covering many of the same points Dan does. He has put together a
reading list: [http://blog.dilbert.com/post/129784168866/the-persuasion-
rea...](http://blog.dilbert.com/post/129784168866/the-persuasion-reading-list)

~~~
swah
In his podcast episode with Tim Ferris he cites again Influence - by Robert B.
Cialdini PhD

------
cturner
The backfire effect has had a lot of airplay. I've just now made a quick scan
of the study, but not read in detail ([https://www.dartmouth.edu/~nyhan/nyhan-
reifler.pdf](https://www.dartmouth.edu/~nyhan/nyhan-reifler.pdf)). I don't
think the paper justifies its conclusion that "corrections [..] increase
misperceptions among the group in question".

From the paper, "In other words, the correction backfired – conservatives who
received a correction telling them that Iraq did not have WMD were more likely
to believe that Iraq had WMD than those in the control condition."
([https://www.dartmouth.edu/~nyhan/nyhan-
reifler.pdf](https://www.dartmouth.edu/~nyhan/nyhan-reifler.pdf))

I don't think that connection flows. Rather, I see this: when you take people
who have developed political opinions, and act in a way that suggests insult
to their world-view, some will react with defiance/sabotage.

The study identifies the pre-existing political leanings of the subjects.
Hence, background work has been done to understand a subject's political
persuasion, and the subject knows they have been profiled for this.

Then they isolate an issue which some subjects will know to be contentious
across liberal/conservative lines, and present the subject with a position.
This act (focusing on a vulnerable issue and then preventing evidence that
indicates a clear conclusion) alienates the project from the subject, and sets
them up to be from a rival worldview. Some subjects, particularly the more
politically-aware subjects, will be speculating on the purpose of the study.
Then the study asks the subject to - essentially - calculate one plus one one
on the issue, towards a conclusion that supports the rival worldview.

The people running these studies will be identified by the participants as
members of the intelligentsia. That will have a bearing on subject behavior,
and will further encourage defiance in some subjects. In my scan, I didn't see
signs of effort made to disguise or water down the focus of the study.

------
jdmoreira
I'm still watching but it took an interesting turn at the 30 min mark :)

------
x0re4x
C++ Zealot Declares: C++ Declining In Embedded Because Not Enough Preaching To
Resistant C Programming Infidels

------
hellofunk
I fail to understand why his discussion of the words "merry, marry, Mary" and
photos of him with Biden and Obama had any relevance to this discussion. That
was a very odd interlude in an otherwise fairly interesting talk.

------
JohnLeTigre
You won't convince me that c++ is as good as c simply by representing a plain
old structure as a class or by talking about the type of arrays.

To me, data-oriented design is more interesting:
[https://www.youtube.com/watch?v=rX0ItVEVjHc](https://www.youtube.com/watch?v=rX0ItVEVjHc)

