[penguicon-general] A couple of thoughts about programming
Rob Landley
rob at landley.net
Tue May 1 10:55:10 CDT 2007
On Tuesday 01 May 2007 1:40 am, Charles Ulrich wrote:
> On 4/28/07, Clay Dowling <clay at lazarusid.com> wrote:
> > Catherine Olanich Raymond wrote:
> > > On Friday 27 April 2007 6:19 pm, Rob Landley wrote:
> > >> Why to program in C.
> > > Sounds like fun. Anybody want to join Rob for any of these?
> >
> > I'd be up for this one. I have a couple of projects at the moment that
> > demonstrate -exactly- why C is great.
>
> Yeah, Clay is your guy for this. He did a GLLUG presentation once on
> why C doesn't have to be a bad choice for web apps and I have to
> admit, he made a pretty convincing case.
Also "the advantages of C over C++".
C is simple, a small compact language you can fit in your head. C++ stopped
being so in about 1992.
C has a clear design goal: it's a portable assembly language that fairly
closely matches what the computer is actually doing. C++ adds things like
templates, subclassing, and operator redefinition to intentionally hide what
the machine is doing, but C++ doesn't go all the way to a modern 4th
generation language.
Due to its clear role as a portable assembly language, at a low level most
other software is written in C. Not just your operating system kernel, but
the compilers and runtimes for other languages like perl, python, java, ruby,
and php. It makes less sense to write application software (like a word
processor) in C these days because a programmer can get 10 times as much
functionality implemented per hour in a higher level language like python.
But your speed-constrained video codec and flash runtime are probably going
to be C.
A modern language (like python or ruby) has a runtime and references instead
of pointers. This makes it easy to do bytecode, exceptions, garbage
collection, and true runtime type identification (where you can attempt to
access an arbitrary member of an arbitrary object, and if it doesn't have a
member by that name you can catch the exception and add such a member to the
object). These all go together as a package (explaining this properly is a
panel of its' own).
C++ instead went with object orientation as its central theme, which was the
Hot New Thing in the 1990's but turned out not to be such a big deal. You
can do object oriented design in C; have a structure with data shared by a
bunch of functions, make the functions take a "this" pointer as their first
argument and dereference this inside the function. If you want virtual
methods, put function pointers in the structure and call 'em. The Linux
kernel is full of object oriented pure C (the VFS layer). The syntax for
doing this in C is actually only about 5% more verbose than doing it in C++,
and it's a lot clearer what the machine is actually _doing_.
When modern languages started to emerge, C++ went "oops, THAT'S what we should
have been thinking about" and started retrofitting the new concepts. But it
didn't have a runtime (instead it links in a big library). Its' attempt at
exceptions bloated the heck out of both the stack and the code. Garbage
collection is really hard in C++, because it requires references instead of
pointers. (A reference is a pointer you can't do math on, it _always_ points
to either a valid object or to NULL; without this property doing garbage
collection is insanely complicated.) But C++ can't give up pointers without
losing the underlying C, which was part of the definition of the language, so
garbage collection never made it into the standard.
And then there's templates, which are C++'s attempt to do runtime type
identification at compile time. This makes about as much sense as attempting
to do garbage collection at compile time. Templates pretend to hide
complexity, but you have to understand exactly what the template expands to
in order to have any hope of reliably using (or debugging) it.
C++ tried to leverage the popularity of C (it's the universal assembly
language everything else is written in), but got the disadvantages of C too
(pointers, manual memory allocation, static typing fixed at compile time).
As a result C++ wound up in a weird no-man's land between C and Python,
neither fish nor fowl and sucking at both niches. It has managed to con some
people into thinking it's as good as C++ for writing low level infrastructure
(qt is a big case in point), but when successful such projects generally
refuse to use things like templates and instead use C++ it in its original "C
with classes" intent, as a slightly smaller syntax for doing object
orientation and nothing more.
C++ has grown lots of mechanisms to "manage" complexity, and in doing so
actually _encourage_ complexity. (For example, classes weren't enough so
they had to add scopes.) In C, the solution to this problem is to step back
and clean up the code, removing stuff to REDUCE complexity.
"public/protected/private" are based on a mindset of not trusting programmers
to be any good or to understand how the thing actually works. Not only is
hiding the implementation antithetical to both good programming and to open
source, but if you expect bad programmers you GET bad programmers.
C++ is popular in corporate environments for the same reason cobol is: it's
designed to satisfy managers, not programmers. It's a "drone language",
aimed at faceless worker bees. The fundamental assumptions are that
programmers are interchangeable cogs, and programmers can't be trusted. If
it was actually true that a random programmer off the street couldn't do much
worse than the people who originally wrote the code (which
public/protected/private attempt to enforce), this would not be an
_advantage_ of the language. But it seems like one to pointy-haired types.
The other big corporate assumption is that once code is written and working,
it should never be touched again. Corporations treat code as an asset, which
means that existing code, once written, has a dollar value attached.
Therefore, removing old code is a waste of money. If throwing old code away
makes no economic sense, then the only thing you can ever do is add more
code, layer upon layer of subclasses, to get the behavior you want. This
sounds crazy but it's VERY common in corporate environments: we paid for that
code, and you WILL use it. Corporations LOVE subclassing.
Management types think the urge to rewrite is simple programmer ego: obviously
every programmer thinks they're better than every other programmer because
they're all arogant, and this must be repressed. In reality, programmers not
only try to constantly improve code, but try to adapt code to the task in
front of them. If the current task is not the same as the previous task, why
would you assume the code from the previous task is a perfect fit for the
current task. Good programmers also constantly strive to remove unneeded
code, to clean things up. If you want to share code between projects, use a
shared library; otherwise code that this project isn't using shouldn't be in
this project.
Oh, don't combine C++ and shared libraries. Just don't. That's a can of
worms that would require a whole post of its own to even START to address,
but the big one is you have to build the library and everything using the
library with the exact same compiler version. And no, wrapping "extern C"
around a function that returns a pointer to a class instance doesn't actually
help matters, and yes I've seen this. C++ pretends you don't have to
understand what's going on under the covers (so it gets people who don't even
try) and then makes 10 times as much stuff happen under the covers because
nobody's watching to keep the complexity down...
I'll stop now.
Rob
More information about the penguicon-general
mailing list