I was reading some interesting articles about realizing object-oriented programming in ANSI C. It seems that most people commenting on these articles think this is a good idea in general. I want to say something different, though. In my view, it is fine to realize some basic OOP bits such as encapsulation and constructor, but we should not go too far.
In fact, most of well-formed C projects contain some basic OOP bits. To avoid using too many global variables or a long list of arguments of a C function, we usually put related variables in a struct and transfers a pointer to the struct between functions. Frequently we define functions to (de)allocate memory for the struct. Occasionally we even put the definition of the struct in .c files rather than .h to completely hide the details of the struct. This is basic encapsulation and (de)constructor. We frequently use “static” functions inside a source file. This is private function. We should stop here, though.
Most of these OOP-in-C articles further mimic methods, inheritance, messaging and more OOP bits. However, all these things come at the cost of speed and/or space efficiency. For example, although we may use pointers to functions to mimic methods, pointers take memory and prevent the compiler from inlining simple functions. If we really want to following the C++ methodology to make everything objects, the overhead on these bits is huge.
The most frequent motivation to using OOP in C is because the programmer needs portability while (s)he only knows OOP or thinks OOP is better. I do not want to argue if OOP is better than procedural programming, but I really think it is big fault to try to mimic all the OOP bits in C in an unnecessarily complicated way given all the overhead on performance. If you have to use C in your project, learn and be good at procedural programming which has been proved to be at least as good as OOP on a lot of practical applications.
interesting comment.
I heard there is also OO coding style in Linux Kernel. When programs go further complicated, do something in OO may reduce the load to designed a big system.
It is also the original significance: breaking code into segments with proper authorizing and simplifying the process to design a system.
It is true whether or not choose OOP is a trade-off between efficiency and flexibility.
Well, I miss C++ template, but I do not feel OOP ideas help much in my mid-scaled projects. With procedural programming, developers also break a big system down to small bits. In addition, as I said, most well-formed C projects have encapsulation and (de)construction, but I do not know if these few features alone can be said as OO coding style. In my view, OOP in C++ and procedural programming in C have similar efficiency and flexibility. I was just saying that implementing too many OOP features in C hurts performance.
You can do OOP in assembly but you can be sure you know what you are doing if you build it yourself.
The problem with C++ seems to me they are adding too many overcomplex features but not simplifying anything.
Take autopointers. The idea is yet another thing to obscure memory management but you should either go for managed memory or keep at a lower level, not a horrid in between state. With autopointers you make many small allocations, and you are doing extra allocations for the pointer itself. AND you can easily accidentally assign it to the wrong thing anyway…so what’s the benefit? It’s not only worthless but a very harmful and misguided practice.
A pointer should be a pointer, not some vague idea that you have no idea what it’s really doing on a particular platform. Types with pointers is very likely a mistake, and not the only possible mechanism to avoid assignment to invalid object types.
Memory and pointers are easy concepts but C++ completely obscures them instead of forcing programmers to just use them from the start.
Inheritance is really not something to worry about, though. It’s not the performance issue many make out or it’s not if you are using it in places that make sense.
The biggest performance problem with OOP is that C++ has awful memory allocation that just can’t handle lots of small allocations (such as autopointers) which causes huge waste in space and time.
The real problem, though, is overcomplexity. If you use anything in STL at all, it’s not long before you have to start coding every single thing around the STL in their (very very silly) paradigm. The new casts are a good illustration of what’s wrong with C++’s direction – if you are consciously throwing out constness ever, and I mean EVER, you are doing something very wrong or using a very poorly made library (usually latter).
Templates themselves are nice and would also be a good addition to C, but the way they are used by most people is just awful, including STL.
What really needs to happen is to ditch C and C++ completely. Many of the C++ OOP features are just halfassed and barely functional. IE try and catch, namespaces, having to tell the compiler to use virtual destructors when overloaded. There’s so many old features lingering that it makes it so that most people are also basically redefining C++ as they go, making their code useless to anyone who doesn’t use their exact same paradigm.
@Antiguru
I agree with you in general. C++ is unnecessarily overcomplicated. I only use C these days, although I used to systematically study STL source code back to a few years ago.
I am thinking why C++ is so popular. There must be a reason. In my view, the magic of C is to write a variety of programs from a few simple rules. But to combine these rules effectively and efficiently, you must have a programmer’s mind which is not possessed by everyone. Many people after C classes cannot work on real projects at all. They do not know where to start from simple rules. In contrast, C++ gives you many complex rules. After C++ classes, you feel you have really learned something. You can write reasonably good programs without really grasping the essence of programming. For many people, remembering knowledges is much easier than using knowledges. Simplicity attracts someone but also pushes someone away. To this end, C++ lowers the threshold of a qualified programmer.
However, even so I think the adoption of C++ is a historical mistake. To be compatible with C libraries (not C source code), D does much better. It is just too late.
I think you might be interested by http://ooc-lang.org/ (and by ‘you’, I mean both the writer and the readers of this blog)
It’s my attempt to make an OOP language which translates to C and sucks less than C++ (a very unfair description but it puts it into context.)
Anyway – you can learn more about it on the homepage, and this page http://ooc-lang.org/syntax should give you a good fell of its syntax.
Note that it’s still in early development, and ides are welcome (we can be found at #ooc-lang on Freenode)
I’m a fan of the blog author’s take on generic programming in C (that is, to use type-deft macros). I think this beats a lot of the “full OOP in C” methodologies hands-down. The only real issue is that the syntax for #define macros using token-pasting (##) to sub in pieces of variable/function/type-names, etc is downright ugly, especially the \ on every line ending.
What C really needs is a better macro system. Perhaps no more capable than what we have today in C99 (although bringing in gcc’s typeof would be nice), but just with better syntax, more akin to C++ template syntax.
I guess someone could do that today with a new front-end pre-processor that generated #defines from a nicer syntax.
@foo
If I were asked to design C1x, I would surely add C++ template (but nothing else) to C even at the cost of simplicity. I do not quite like macros, but this is the only efficient way to achieve generic programming in C.
The worst thing with macros and meta programming is that the time you win by using abstraction you spend on compilation. I really became allergic to those templates, as I had enough of ugly ones on an even uglier project. Once people start to use templates, there mind fails to switch to other approaches. The result is bloat of bloat. But I do not see any problems with inheritance or polymorphism in C. For sure in some cases the non-inlining and other issues with polymorphism would cost you something, but I am not sure that this would cause serious performance issues. Maybe in 1% of the running code, where you can optimize, force inlining etc. etc. I am writing lot of code for embedded devices, but seriously, no real performance issues so far. Instead the surprises come from somwhere else: http://www.mobiphil.com/2010/04/when-faster-is-slower-libc-world/
As long as the CPU time is evenly distributed to different parts of code or your program can finish in seconds, you do not need to worry too much about efficiency. But there are times a program runs for hours and most of time goes to a few lines where using template/macro delivers considerable improvements. For example, C++ sort can be over 10X faster than libc’s qsort (see also this).
I think there is no perfect solution to generic programming. We have to trade simplicity for efficiency or vice versa. But if let me choose between simplicity and efficiency, I am inclined to efficiency and template/macro is the only solution. At the same time, I also think C++ STL is somehow abusing template, although all C++ programmers would disagree.
I definitely agree with you. When I have a class of say, 10 member variables (assume all int) and 20 methods to operate upon them, C++ would give me 40 bytes per instance. Since the methods are shared between the instances, it will occupy constant size in memory. Where as to achieve the same thing with function pointers in C, the size would become 40 + 160 = 200 bytes per instance of the structure – which is clearly wastes the memory by 5 times.
When I designed my project in C, for the same reasons you mentioned, I refrained from implementing pure OOP concepts in C.