librelist archives

« back to archive

C verses c++

C verses c++

From:
John Aughey
Date:
2010-07-15 @ 21:56
My next debate will be vi verses emacs, but let's get this one out of the 
way too...

I'm not advocating going all OO on the core of mongrel2, but I'm looking 
at a lot if code that is overly complicated due to needing to deal with 
bstring and other memory management tasks. Lots of places to miss a free 
or double free where C++ destructors could take care of those tasks. Just 
using std::string would reduce the mm noise and make the code easier to 
read and reduce the chances of memory leaks. 

John Aughey

Re: [mongrel2] C verses c++

From:
Zed A. Shaw
Date:
2010-07-16 @ 01:45
On Thu, Jul 15, 2010 at 05:56:18PM -0400, John Aughey wrote:
> My next debate will be vi verses emacs, but let's get this one out of
> the way too...
> 
> I'm not advocating going all OO on the core of mongrel2, but I'm
> looking at a lot if code that is overly complicated due to needing to
> deal with bstring and other memory management tasks. Lots of places to
> miss a free or double free where C++ destructors could take care of
> those tasks. Just using std::string would reduce the mm noise and make
> the code easier to read and reduce the chances of memory leaks. 

First, I'm an old school C++ coder too, but quit using it during the
"Great Template Metaprogramming Plague of 2000".  Recently I wrote
MulletDB in C++ using the Grace framework and it was pretty nice, but
seriously overkill for what mongrel2 does.

So, the non-rant answer is, well for something like this, where the core
of the whole system is fairly simple, C is really the best because it is
the lowest friction access to all the POSIX stuff you need.  Because the
majority of the system's work is inside POSIX and system calls, C++ just
becomes a huge bother to do the same thing.  Just something as simple as
sockets becomes a major operation, and the OOP doesn't help.


Now for the rant answer, and if you like C++, stop right here:

With that being said, and no offence to you, but everything you said as
C++ advantages are total bunk.  The semantics of destructors are
incredibly confusing, especially with exceptions.  You have to do all
the same memory checks, use valgrind, make sure you've got destructors,
and then that's made more complex by templates, object lifecycles,
exception rules, etc..  Frankly C++ doesn't have better memory
management than C, it just has more complex management.

Proof of that is how I had to use valgrind to find a memory leak in 0MQ.
No matter what, unless the language has a GC built-in, then C will have
simpler and more predictable memory usage.

Next, the string support is idiotic.  You seriously haven't tried to just
craft basic strings in c++ have you?  Something as simple in *every*
language as:

bstring test = bformat("I want %d ponies", count);

Turns into a giant mountain of bizarre << output to a pseudo file like
thing that has a massive chain of inheritance and is slow as dirt.  The
type safety on these string outputs means you're constantly augmenting
all your own types with converters and friend functions just so you can
put crap into a damn string.  I couldn't imagine trying to use the
string output stream stuff to craft messages and things.  It'd be a
nightmare, and I know because I tried to do it.

The flaw of C++ strings is they tried to make *formatting* a string type
safe.  This meant very basic operations that should be nothing more than
"turn type into a display format and shove in here" get piled on with
huge amounts of type conversion, friend functions, and stupidity that
it's needed.  Really, format strings are the way to go, and modern
languages should support the concept because it's both type safe *and*
easy to use.

Even something as simple as casting a float to an int is a pain in the
ass involving some weird template like syntax that frankly makes no
sense.

Next is all the bizarre fascination with const.  For some odd reason C++
loves to make you slap const on every part of a declaration, and yet I
get the same end result as C: a function is called.  You'll find crap in
C++ like const *const char &, and hell if anyone knows what that really
means since even though the pointer to a const to a const reference is
consted to hell and back, oh look you can still increment it.  They'd
have been better off to just invent a new keyword:
doesnotfuckingchange and stop there.

Then there's the stupidity of templates or even just basic class
structures forcing your code to gravitate into .h files, the problem of
having to jump through hoops just to get at basic POSIX C functions,
problems with ABI, horrible error messages, and C++ for Mongrel2 just
becomes a major pain in the ass.

Now, next comes the answer "oh just use boost".  Riiiiiigghhtt, boost is
soo much more usable.  Remember the Plague of 2000?  If I wanted to fry
my brain trying to figure out how to add two numbers with templates I'd
go use LISP.  Boost is also huge, takes forever to build, is almost
always out of date on every distro, and people avoid projects that
depend on it when building systems.

For MulletDB with Grace C++ was awesome, but for Mongrel2, which is a
very simple thing in C, it turns out that C++ is just a pain in the ass
for very little benefit.

Anyway, the point of the project is that, even though I did it in C, you
can use whatever you want for your stuff.  I'm good at C, and I can make
it work with very little code, so no need to worry since it will never
get in your way.

-- 
Zed A. Shaw
http://zedshaw.com/

Re: [mongrel2] C verses c++

From:
John Aughey
Date:
2010-07-16 @ 03:51
Ok, let me take a deep breath and.... (I'm going to agree with a lot,
but...)

On Thu, Jul 15, 2010 at 8:45 PM, Zed A. Shaw <zedshaw@zedshaw.com> wrote:
>
> First, I'm an old school C++ coder too, but quit using it during the
> "Great Template Metaprogramming Plague of 2000".  Recently I wrote
> MulletDB in C++ using the Grace framework and it was pretty nice, but
> seriously overkill for what mongrel2 does.
>

I was taught C++ as the first class to be taught that at Purdue back in '93.
 I really never used [got] it until I started using it professionally.  I
got back into it during that template plague working with ACE/TAO out of
WashU.  I have since recovered from that.


> So, the non-rant answer is, well for something like this, where the core
> of the whole system is fairly simple, C is really the best because it is
> the lowest friction access to all the POSIX stuff you need.  Because the
> majority of the system's work is inside POSIX and system calls, C++ just
> becomes a huge bother to do the same thing.  Just something as simple as
> sockets becomes a major operation, and the OOP doesn't help.
>

To this and to a lot of the rest of the rant, I'd say to use the features of
C++ that are comfortable and make sense to help the code.  You don't need to
OOP the whole thing.  It might migrate that way and you can kill ugly
template metaprogramming crap, and maybe, just maybe, it might make sense to
OOP parts of it.


> Now for the rant answer, and if you like C++, stop right here:
>

Never miss a good debate on this...


> With that being said, and no offence to you, but everything you said as
> C++ advantages are total bunk.  The semantics of destructors are
> incredibly confusing, especially with exceptions.  You have to do all
> the same memory checks, use valgrind, make sure you've got destructors,
> and then that's made more complex by templates, object lifecycles,
> exception rules, etc..  Frankly C++ doesn't have better memory
> management than C, it just has more complex management.
>

Sure, you can make C++ crazy and ugly.  C isn't pretty either, especially
when they try to do C++ things with libraries such as bstring.    Exceptions
are just a start.  I agree C++ doesn't have better memory management, but
the objects can handle the memory themselves.

Take for example your Unixy_pid_file function.  It calls bstr2cstr and
creates another char* object.  Apparently this needs to be freed down below,
but I don't know bstring that well to know it needs to be freed.  There are
two exit points, and the error: path checks to see if it needs to be freed
and does do.  Same for the non-error path.

Confusion I see is, there's an internal alloc that needs to be freed inside
bstr2cstr that you need to know what bstr2cstr does to know that the memory
needs to be freed.  To add to this confusion, there is a bdata method which
returns a const char * (you don't like const below) and doesn't need to be
freed.  Both bdata and bstr2cstr seems to yield the same result with the
added bonus that the  programmer is required to know they have to free a
result of bstr2cstr.  Even worse, the same .c file uses both these methods
in different functions for much the same purpose.


> Proof of that is how I had to use valgrind to find a memory leak in 0MQ.
> No matter what, unless the language has a GC built-in, then C will have
> simpler and more predictable memory usage.
>

Well sure.  I'd argue that C++ can be more complex because inherently you're
going to new lots of objects and may not handle them correctly.  Smart
pointers can help, but those can be even more confusing.  Again, you don't
need to go that crazy with them.  C is just as unpredictable because it's
news to me that bstr2cstr did an alloc behind the scenes that needed to be
freed while bdata didn't (or does it).


> Next, the string support is idiotic.  You seriously haven't tried to just
> craft basic strings in c++ have you?  Something as simple in *every*
> language as:
>

I'll stop you here and recommend using CBString as a C++ wrapper around
BString.  I agree the C++ << streaming operators go ape nuts crazy with the
iostream classes.  QString gives you formatting, but I'm guessing you're not
interested in making a dependency on Qt; nor would I for this project.


> Even something as simple as casting a float to an int is a pain in the
> ass involving some weird template like syntax that frankly makes no
> sense.
>

You can use C style casts.


> Next is all the bizarre fascination with const.  For some odd reason C++
> loves to make you slap const on every part of a declaration, and yet I
> get the same end result as C: a function is called.


I'll advocate for const correctness.  It helps keep people from screwing
things up.  You can, and do, const types in C.  fopen takes a const char *
like it should.  If it took a char* I'd be worried.


> You'll find crap in
> C++ like const *const char &, and hell if anyone knows what that really
>

Except for the reference part, C offers you all the const uglyness of C++.


> Now, next comes the answer "oh just use boost".  Riiiiiigghhtt, boost is
> soo much more usable.  Remember the Plague of 2000?  If I wanted to fry
> my brain trying to figure out how to add two numbers with templates I'd
> go use LISP.  Boost is also huge, takes forever to build, is almost
> always out of date on every distro, and people avoid projects that
> depend on it when building systems.
>

I use boost only for smart pointers which doesn't require you to compile.
 I'd even yank out what I need for smart pointers and leave the rest of
boost to rot.  I think boost and ACE should get together and just have a
huge template orgy.


> Anyway, the point of the project is that, even though I did it in C, you
> can use whatever you want for your stuff.  I'm good at C, and I can make
> it work with very little code, so no need to worry since it will never
> get in your way.
>

This discussion got started when I was looking at unixy.c and saw a lot of
bstring allocs and frees that would be unnecessary with a good object system
handling that memory.  I worked with Asterisk for a while and their memory
allocating and copying is just crazy.  Look at voicemail.c for an example.
 Half the code deals with copying simple strings around and making sure the
frees are done right.  I saw similar complexities in this one file and
different ways of achieving the same end result with different memory
management requirements imposed on the programmer.

John

Re: [mongrel2] C verses c++

From:
Alex Gartrell
Date:
2010-07-16 @ 04:43
At the risk of oversimplifying the issue greatly, I'd much rather spend my
time figuring out how to make C code faster than trying to figure out how to
make C++ code faster.  I'm unconvinced that there's a programmer out there
who can grok C++ (and by grok, I mean understand it down to the
instructions) as quickly or as easily as they can grok C.  Hiding complexity
is definitely a double-edged sword here, especially when complexity is
generally the enemy of performance and that's what (I believe) we're really
after here.

But mostly, even beautifully crafted C++ (like Chromium) is waayyyy less
obvious than the rarely touched C in Linux /net.  So, pretty please, keep it
in C for the sake of simple folks like myself.

Just my 2 cents :)

On Thu, Jul 15, 2010 at 11:51 PM, John Aughey <jha@aughey.com> wrote:

> Ok, let me take a deep breath and.... (I'm going to agree with a lot,
> but...)
>
> On Thu, Jul 15, 2010 at 8:45 PM, Zed A. Shaw <zedshaw@zedshaw.com> wrote:
>>
>> First, I'm an old school C++ coder too, but quit using it during the
>> "Great Template Metaprogramming Plague of 2000".  Recently I wrote
>> MulletDB in C++ using the Grace framework and it was pretty nice, but
>> seriously overkill for what mongrel2 does.
>>
>
> I was taught C++ as the first class to be taught that at Purdue back in
> '93.  I really never used [got] it until I started using it professionally.
>  I got back into it during that template plague working with ACE/TAO out of
> WashU.  I have since recovered from that.
>
>
>> So, the non-rant answer is, well for something like this, where the core
>> of the whole system is fairly simple, C is really the best because it is
>> the lowest friction access to all the POSIX stuff you need.  Because the
>> majority of the system's work is inside POSIX and system calls, C++ just
>> becomes a huge bother to do the same thing.  Just something as simple as
>> sockets becomes a major operation, and the OOP doesn't help.
>>
>
> To this and to a lot of the rest of the rant, I'd say to use the features
> of C++ that are comfortable and make sense to help the code.  You don't need
> to OOP the whole thing.  It might migrate that way and you can kill ugly
> template metaprogramming crap, and maybe, just maybe, it might make sense to
> OOP parts of it.
>
>
>> Now for the rant answer, and if you like C++, stop right here:
>>
>
> Never miss a good debate on this...
>
>
>> With that being said, and no offence to you, but everything you said as
>> C++ advantages are total bunk.  The semantics of destructors are
>> incredibly confusing, especially with exceptions.  You have to do all
>> the same memory checks, use valgrind, make sure you've got destructors,
>> and then that's made more complex by templates, object lifecycles,
>> exception rules, etc..  Frankly C++ doesn't have better memory
>> management than C, it just has more complex management.
>>
>
> Sure, you can make C++ crazy and ugly.  C isn't pretty either, especially
> when they try to do C++ things with libraries such as bstring.    Exceptions
> are just a start.  I agree C++ doesn't have better memory management, but
> the objects can handle the memory themselves.
>
> Take for example your Unixy_pid_file function.  It calls bstr2cstr and
> creates another char* object.  Apparently this needs to be freed down below,
> but I don't know bstring that well to know it needs to be freed.  There are
> two exit points, and the error: path checks to see if it needs to be freed
> and does do.  Same for the non-error path.
>
> Confusion I see is, there's an internal alloc that needs to be freed inside
> bstr2cstr that you need to know what bstr2cstr does to know that the memory
> needs to be freed.  To add to this confusion, there is a bdata method which
> returns a const char * (you don't like const below) and doesn't need to be
> freed.  Both bdata and bstr2cstr seems to yield the same result with the
> added bonus that the  programmer is required to know they have to free a
> result of bstr2cstr.  Even worse, the same .c file uses both these methods
> in different functions for much the same purpose.
>
>
>> Proof of that is how I had to use valgrind to find a memory leak in 0MQ.
>> No matter what, unless the language has a GC built-in, then C will have
>> simpler and more predictable memory usage.
>>
>
> Well sure.  I'd argue that C++ can be more complex because inherently
> you're going to new lots of objects and may not handle them correctly.
>  Smart pointers can help, but those can be even more confusing.  Again, you
> don't need to go that crazy with them.  C is just as unpredictable because
> it's news to me that bstr2cstr did an alloc behind the scenes that needed to
> be freed while bdata didn't (or does it).
>
>
>> Next, the string support is idiotic.  You seriously haven't tried to just
>> craft basic strings in c++ have you?  Something as simple in *every*
>> language as:
>>
>
> I'll stop you here and recommend using CBString as a C++ wrapper around
> BString.  I agree the C++ << streaming operators go ape nuts crazy with the
> iostream classes.  QString gives you formatting, but I'm guessing you're not
> interested in making a dependency on Qt; nor would I for this project.
>
>
>> Even something as simple as casting a float to an int is a pain in the
>> ass involving some weird template like syntax that frankly makes no
>> sense.
>>
>
> You can use C style casts.
>
>
>> Next is all the bizarre fascination with const.  For some odd reason C++
>> loves to make you slap const on every part of a declaration, and yet I
>> get the same end result as C: a function is called.
>
>
> I'll advocate for const correctness.  It helps keep people from screwing
> things up.  You can, and do, const types in C.  fopen takes a const char *
> like it should.  If it took a char* I'd be worried.
>
>
>> You'll find crap in
>> C++ like const *const char &, and hell if anyone knows what that really
>>
>
> Except for the reference part, C offers you all the const uglyness of C++.
>
>
>> Now, next comes the answer "oh just use boost".  Riiiiiigghhtt, boost is
>> soo much more usable.  Remember the Plague of 2000?  If I wanted to fry
>> my brain trying to figure out how to add two numbers with templates I'd
>> go use LISP.  Boost is also huge, takes forever to build, is almost
>> always out of date on every distro, and people avoid projects that
>> depend on it when building systems.
>>
>
> I use boost only for smart pointers which doesn't require you to compile.
>  I'd even yank out what I need for smart pointers and leave the rest of
> boost to rot.  I think boost and ACE should get together and just have a
> huge template orgy.
>
>
>> Anyway, the point of the project is that, even though I did it in C, you
>> can use whatever you want for your stuff.  I'm good at C, and I can make
>> it work with very little code, so no need to worry since it will never
>> get in your way.
>>
>
> This discussion got started when I was looking at unixy.c and saw a lot of
> bstring allocs and frees that would be unnecessary with a good object system
> handling that memory.  I worked with Asterisk for a while and their memory
> allocating and copying is just crazy.  Look at voicemail.c for an example.
>  Half the code deals with copying simple strings around and making sure the
> frees are done right.  I saw similar complexities in this one file and
> different ways of achieving the same end result with different memory
> management requirements imposed on the programmer.
>
> John
>

Re: [mongrel2] C verses c++

From:
Zed A. Shaw
Date:
2010-07-16 @ 05:52
On Fri, Jul 16, 2010 at 12:43:47AM -0400, Alex Gartrell wrote:
> At the risk of oversimplifying the issue greatly, I'd much rather spend my
> time figuring out how to make C code faster than trying to figure out how to
> make C++ code faster.  I'm unconvinced that there's a programmer out there
> who can grok C++ (and by grok, I mean understand it down to the
> instructions) as quickly or as easily as they can grok C.  Hiding complexity
> is definitely a double-edged sword here, especially when complexity is
> generally the enemy of performance and that's what (I believe) we're really
> after here.
> 
> But mostly, even beautifully crafted C++ (like Chromium) is waayyyy less
> obvious than the rarely touched C in Linux /net.  So, pretty please, keep it
> in C for the sake of simple folks like myself.

I think this leads to another key point:  I know *all* of my key
mistakes in C and I write very good clean C code, probably better C code
than other people write most languages.  I spent a year doing detailed
statistics analysis of all my error mistakes and rates and crafting ways
to prevent them.  Something I don't recommend anyone else do unless
they're insane like me, but the end result is, my C code is psychic.

For example, just look at any place in the code where I have it tell you
to tell me it broke.

In c++ I don't have this same knowledge, so it would actually be a less
stable and harder to read system than C until I did this same analysis.
Just isn't going to happen.

-- 
Zed A. Shaw
http://zedshaw.com/

Re: [mongrel2] C verses c++

From:
Fred Alger
Date:
2010-07-16 @ 18:29
> Take for example your Unixy_pid_file function.  It calls bstr2cstr and 
creates another char* object.  Apparently this needs to be freed down 
below, but I don't know bstring that well to know it needs to be freed.  
There are two exit points, and the error: path checks to see if it needs 
to be freed and does do.  Same for the non-error path.
> 
> Confusion I see is, there's an internal alloc that needs to be freed 
inside bstr2cstr that you need to know what bstr2cstr does to know that 
the memory needs to be freed.  To add to this confusion, there is a bdata 
method which returns a const char * (you don't like const below) and 
doesn't need to be freed.  Both bdata and bstr2cstr seems to yield the 
same result with the added bonus that the  programmer is required to know 
they have to free a result of bstr2cstr.  Even worse, the same .c file 
uses both these methods in different functions for much the same purpose.
I'm gonna call bullshit on this, because it's a pretty standard C paradigm
to have functions that return a heap-allocated object.  In fact, reading 
Unixy_pid_file, I can tell that pid_path is a heap-allocated variable 
because the programmer calls free() on the pointer in both the normal and 
error return paths.  Having read, that, and without even cracking open the
bstring docs, I realize that bstr2cstr returns a pointer to a 
heap-allocated C string, and leaves memory management up to the caller.

Meanwhile, if this were C++, sure, the destructor would be automatically 
called when the variable left scope, but at what cost in complexity?  
Dozens of header files in a bizzare-world class hierarchy?  Even assuming 
that the memory management of the string class used was _perfect_ and I 
never had to look at it, ever, it'd save me what, two lines of free() 
calls?

Oh, and C is object oriented (c.f. the stdio library, POSIX system calls, 
etc.), it's just not anally retentive symbol mangling insanity like C++; 
it leaves the programmer free to implement small, simple protocols, 
resulting in tight, clean, simple code like Mongrel2's which reads like a 
book.  Calling object->method() is just syntactic sugar anyhow.

Seriously, just relax, write clean code, and trust valgrind, gcc -Wall, 
and code review to catch your mistakes.  No need to use a chainsaw to cut 
a steak.

best,
- Fred Alger.
@_phred

Re: [mongrel2] C verses c++

From:
Zed A. Shaw
Date:
2010-07-16 @ 19:02
On Fri, Jul 16, 2010 at 02:29:51PM -0400, Fred Alger wrote:
> > Take for example your Unixy_pid_file function.  It calls bstr2cstr
> > and creates another char* object.  Apparently this needs to be freed
> > down below, but I don't know bstring that well to know it needs to
> > be freed.  There are two exit points, and the error: path checks to
> > see if it needs to be freed and does do.  Same for the non-error
> > path.
>
> ... 
>
> Seriously, just relax, write clean code, and trust valgrind, gcc
> -Wall, and code review to catch your mistakes.  No need to use a
> chainsaw to cut a steak.

I think another way to say this, is you can find janky weird things to
nitpick at in any language.  But, in the code mentioned above, it's a
very common pattern and used consistently everywhere, so anyone who
didn't know about it could pick it up quick.  I'd have the same thing in
C++ with all the destructor protocols.  In Python I'd have things about
references to worry about (although rarely).

It just comes down to not mattering nearly as much as people make it
seem.  Show me any code base and in about 10 minutes I can find things
to complain about, for the very simple reason:

Coding is hard.



-- 
Zed A. Shaw
http://zedshaw.com/

Re: [mongrel2] C verses c++

From:
Zed A. Shaw
Date:
2010-07-16 @ 05:49
On Thu, Jul 15, 2010 at 10:51:15PM -0500, John Aughey wrote:
> To this and to a lot of the rest of the rant, I'd say to use the features of
> C++ that are comfortable and make sense to help the code.  You don't need to
> OOP the whole thing.  It might migrate that way and you can kill ugly
> template metaprogramming crap, and maybe, just maybe, it might make sense to
> OOP parts of it.

Well, then it'd....just be the C I'm using right now.  Right?  Except,
having to use odd includes and then deal with people afraid to hack on
it because C++ is even more scary and weird than C.

Anyway, not really going to go further into it.  The project's in C and
some Python, but it's language agnostic so nothing's going to prevent
other people from using any other language with it.

That's not too big a deal right?

-- 
Zed A. Shaw
http://zedshaw.com/