

The C++ bashing season is back - edw519
http://eli.thegreenplace.net/2009/10/17/the-c-bashing-season-is-back/

======
jrockway
_µTorrent is written in C++, and you could never, ever, make it so fast and
small using any other language._

Citation needed. I think it could be done easily in Haskell, or Erlang, or
Common Lisp, or even Java. (Actually, I bet it would even be fine in
Perl/Python/Ruby.) A bittorrent client's speed comes from an efficient TCP
stack and some minimal userspace use of non-blocking IO (or lightweight
threads). It's basically glue between epoll (or similar), some disk reads and
writes, and a tiny bit of algorithmic code.

It is unlikely that C++ is the best choice for this sort of application. It
will work and it will be fast, but it will probably be just as fast in safer
languages too.

~~~
kragen
There are other languages you could make it small in, but those languages
probably aren't among them.

Haskell: Hugs 98 is 723K, but it depends on /usr/lib/hugs, which is 7.3M. GHC
can _almost_ do it; I compiled a "hello, world" program with GHC and it "only"
came out to 366K, which is 84K bigger than μTorrent's reported size. With UPX,
however, it packs to 130k. (ocamlopt's tax is in the same range.) Maybe
Haskell would be an option? Or does it bloat up when you include the libraries
you'd need for this?

Erlang: My Erlang install is 97M. I don't know how much of that is minimally
necessary to run things, but /usr/lib/erlang/erts-5.6.3 is 3.6M, 12 times the
size of μTorrent. Stand Alone Erlang (<http://www.sics.se/~joe/sae.html>) is
1.5MB compressed.

Common Lisp: All the Common Lisp implementations are pretty big (SBCL, say, is
53M, of which 25M is the image sbcl.core), and they can't produce a standalone
executable without including most of the environment. So you're starting at
25M.

Java: The JRE on my system is 98 megabytes, so a Java application to run on
Win32 will be 98 megabytes plus the application code. Even if you compile your
app with GCJ, libgcj is 33 megabytes.

Now, you could argue that the size of this stuff isn't relevant because it
isn't specific to your hypothetical Common Lisp implementation of BitTorrent,
but could also be used by whatever other Common Lisp programs the user has
installed. But you would be treating a very-low-probability event as if it
were normal.

Languages — or rather, language implementations — that _could_ make a 300k
runnable BitTorrent client include not just C and C++, but also Forth,
assembly, Pascal, Eiffel, and any number of other fatally flawed niche
languages that don't require hundreds of kilobytes of libraries just to
initialize a process and exit. There are probably also Scheme implementations
that would work.

Just about anything that has a reasonably small bytecode interpreter and lets
you package the rest of your program as bytecode would probably win. x86 code
is pretty grossly bloated by comparison to a good compact bytecode. (But
compressible. See comment above about UPX.)

The only other _practical_ alternative I know of would be Lua, which only
costs you about half of your space budget for the interpreter itself. Lua's
"bytecode" is actually wordcode, but presumably UPX or something similar would
squeeze it down to a reasonable size.

It's my understanding that μTorrent does not need to ship with any shared
libraries to run; the <300k of the executable alone is sufficient. You may
think this is unimportant but I think that is an unconcern based in unusual
wealth: you probably own your own computer to install software on
persistently, probably several of them, you probably have several hundred
kilobits per second of bandwidth to download software with, so you probably
don't care how long it takes to download something or how much of a 256MB USB
pendrive it takes up.

It's certainly true that there are any number of languages you could write a
BitTorrent client in that would be just as _fast_.

~~~
jrockway
But let's face it -- micro-optimizing the space of the image on disk is a
completely useless optimization these days. You are also not including the
shared libraries that the binary uses.

When making my argument in the grandparent post, I did not even consider the
size aspect to be worth discussing. If this is somehow important to you, then
my argument does not apply.

------
fogus
Thank goodness -- the Java bashing season seemed to go on forever.

------
junklight
While I am not even vaguely a fan of C++ (despite making my living writing it
for at least 5 years back in the day) you can have readable multi-programmer
code - look at webkit for example. Its a complex bit of functionality and
there is a lot of it but I spend quite a bit of time knee deep in its code
(for an internal project) and I find myself quite impressed with the quality.

Ok - so one data point doesn't prove anything but it does show that it is
perfectly possible to make good C++ projects.

For me the thing that drives me up the wall is how much _work_ I have to do in
C++ compared to Python to do the same things - I guess some of that is having
not used C++ for a long time. That and the fact I keep typing single quoted
strings in C++ and semicolon line endings in Python.

------
biotech
_For someone the good parts of C++ are exceptions and RAII. For another it’s
templates and STL containers. Each one is picking his own subset, and no one
seems to agree whose subset is better/safer/more comprehensible._

It would be nice to see some clear, thorough coding standards for C++ that
chose a reasonable subset. I haven't found many publicly available apart from
Google's Style Guide: [http://google-
styleguide.googlecode.com/svn/trunk/cppguide.x...](http://google-
styleguide.googlecode.com/svn/trunk/cppguide.xml) . Anyone know of any others?

~~~
spamizbad
It needs more than just coding standards. Someone needs to give C++ the same
treatment Doug Crockford gave Javascript when he wrote _Javascript: The Good
Parts_.

~~~
btn
Kernighan & Ritchie have already written that book.

~~~
0wned
Only partially. C with vectors, strings, references, maps and algorithms added
would be _"C++: The Good Parts"_

~~~
ido
For you ;)

------
cpppppppp
Fine by me, pick your latest toy language and demonstrate how you can write a
toy webserver in 3 lines or a Fibonacci calculator in 3 characters.

When you need to get some real work done give me a call - I just put my rates
up.

~~~
uninverted
I wonder what a language with a three character Fibonacci sequence would be
like. You'd probably need Unicode, if the language wasn't specifically
designed for the Fibonacci sequence.

~~~
mahmud
A "language" that has fibonacci builtin can do it 2 characters. fx. where f is
the name of the fibonacci function and x is a single digit number.

A fibonacci DSL could do it in 1; if all input is expected to be an integral
value and the machine only computes fibonacci values, then typing a single
digit number would have the intended consequence:

    
    
       (loop
         (print (fib (parse-integer (read)))))

------
chanux
You say, Oh that language sucks. This is my favorite language. MyLang Rules!!!

OK you are a jerk.

You say, well I'm not a heavy user of that language. Actually I don't like it
much. But this is my favorite. I like it because of this. Maybe you too like
to try this :).

Hmm... You are great.

That's what I think about language bashing :).

~~~
jrockway
I don't think anyone is "bashing" anything.

C++ has a weird niche. It's as fast as C, but is as high-level as Java... at
first. It has exceptions, it has multiple inheritance, and it has "methods"
(though C++ doesn't call them this, for some reason). This makes it the
perfect language in many people's minds; fast and expressive. Unfortunately,
the stuff that makes it fast is on all the time at the cost of making every
function a potential foot-gun. (I can convert an integer to a pointer at
runtime! I can remove "const", too...)

When you are writing code that needs to execute quickly, you don't want to do
anything that's not related to the task at hand. You want to shovel bits into
the CPU as quickly as possible. This means using native, unboxed types, not
checking preconditions before every operation ("why would the preconditions
ever not be satisfied?"), using trickery like integer-to-pointer casts, etc. C
works this way, and lets you write code that runs very quickly. C++ works this
way too.

The other half of a C++ app, though, is the complex glue code. Most sections
of a "real application" are complicated, but they don't execute often enough
for speed to be too critical. That's where you want safety; lots of self-
checks, boxed types that don't let you misuse them, etc. There is a lot of
complexity to manage, and a team of programmers can't do it; so you want your
language and runtime to help you out.

Unfortunately, C++ doesn't help you out; you are expected to write the non-
time-critical sections of your application they same way you write the
critical sections. Ignore types, manage your own memory, skip polymorphism for
speed, etc. Those are all the default behaviors, and they make it hard to
write reliable code. (It is really worth overwriting random memory just to
avoid a single comparison between an array's length and the index you are
referencing? In a video decoder, yes. In the drop-down menu where the user
picks the kind of TPS report to send, probably not. But guess what the default
behavior is.)

The failure mode of C++ is also quite severe. In Java, flaky code that doesn't
work just returns the wrong answer or dies. In C++, flaky code that doesn't
work can corrupt other parts of the program randomly, and it can even allow
malicious users to inject arbitrary code. There is no failure mode; the
program keeps running incorrectly until something is so utterly wrong that the
OS or machine kills the program. ("Segmentation fault (core dumped)".)

So basically, if you're using C++ correctly, for speed-critical sections of
your application, you could just do it in C; and if you're using it for
applications, you would be better off with anything else; Java, C#, Common
Lisp, Haskell... all much better for higher-level code. You probably won't
notice the runtime speed difference, but you probably will notice the lack of
random crashes because your off-by-one bug overwrote some global state...

