Hacker News new | past | comments | ask | show | jobs | submit login
C++ patterns using plain C (noctua-software.com)
77 points by guillaumec on June 25, 2014 | hide | past | favorite | 94 comments



A complaint about all of the examples is the use of free() directly in main(). I dislike this because it implies that the "create", or "new" used a single call to (m/c)alloc to allocate the returned pointer. While this is the case for the examples, it may not be the case where you are only given a prototype for "base_new" in a header file, and you don't know of its implementation detail.

Such example might be a jagged array where you allocate several chunks of memory, and a final chunk containing the pointers to each one. Freeing the pointer returned for the memory containing these pointers will not free the memory pointed to by each pointer.

The person who wrote the _new function should write the maching _free, since he's really the only one who knows exactly what and how the "object" was allocated and how it needs to be deallocated.

If you find yourself ever writing such _new function without the matching _free, you're doing it wrong.

Even worse is the last list example, as it not clear where, or if memory is even freed at all from the code given. Does one of those macros free up the memory?


> If you find yourself ever writing such _new function without the matching _free, you're doing it wrong.

Agreed. This comes up with some frequency in cross-platform code where somebody coming from Unix (like myself) assumes that there is one `malloc` and it corresponds to one `free`. On Windows, this is not true - when a module is built as debug, the debugging allocators are used which instrument for failures like double-free. So if your debug EXE links a release DLL and tries to `free` something that the DLL has `malloc`ed, your program will quickly abort.


Luckily we have modern C++ where such problems hardly exist :P


That's a valid point. This is the reason why some C API (like the chipmunk physic engine), offer two versions of constructor functions: one that allocates the memory, and one that takes an already allocated pointer.


I also think that asking the user to allocate memory is bad (for OOP) design, because it is leaking information which should be encapsulated into the class. How does the user even know how, or what to allocate in order to work with your "methods"?

A constructor taking a pointer serves a useful purpose - it's the equivalent of a copy constructor.

However, one thing you missed from the examples (quite possibly for simplification of the blog post), is that "proper" OOP design in C is done by having opaque data types in headers, with their fields only in the implementation file - the "methods" you expose in a header all take a pointer to the opaque struct as their first argument, other than the constructor, which returns one. This is how you provide the encapsulation of classes, equivalent to private fields, if you like - which should generally be the case for non-PODS.


Yosefk noted that this idiom in C doesn't require you to recompile all clients when you add a private field, so in some sense it gives you better encapsulation than OOP in C++.


I also think that asking the user to allocate memory is bad (for OOP) design, because it is leaking information which should be encapsulated into the class. How does the user even know how, or what to allocate in order to work with your "methods"?

What? Gods no!

The user knows more about their runtime environment than your objects--indeed, consider this a form of DI for memory management.

Libraries that don't let me override allocations, file access, and logging are very, very bad.


In that case you would inject a function pointer to an allocator (and deallocator), however, the object constructor is the only thing which knows how to allocate the object - consider the jagged array example I gave, or even a linked list - the user has no idea how they're allocated if given just an opaque pointer.


Never do this!

I've worked in a large company with a legacy codebase that attempted to do this in the 90's when C++ & inheritance was the latest-thing. It has turned out to be a real maintenance nightmare for them, it obfuscates normal code scaring off anyone who looks at the it. Lack of tooling is a major issue, try getting eclipse to find the definition of one of your virtual methods...

This is before you consider that all it gives you is inheritance. Wide use of inheritance is an anti-pattern and this gives you the mechanism without the ease-of-use that makes it maintainable.

In summary... AVOID DOING THIS AT ALL COSTS (It will cost you when you need to re-write in a sane way in a few years time).

Anyway... this has been done hundreds of times before, ever heard of CFront??


Welcome back to the 80's, where C++ used to play with macro to make templates and inheritance was only a basic compiler trick.

I can only emphasizes the need to move to real C++ if you want to use C++ idioms, to do it safely and performances wise: here you just opened the gate of Macro error's hell which will be more horrible than anything the C++ could throw at you.


The code in the article is just a plaything, a C programmer wouldn't use any of that and wouldn't use C++ as a starting point for their C implementation. Don't let it reflect negatively on C.


In what way? I have seen several examples of C programs that implemented a form of interfaces using structs of function pointers. The GIMP code base does it, as does the Linux kernel's Virtual File System layer. This is a good overview: https://www.kernel.org/doc/Documentation/filesystems/vfs.txt


As C preprocessor macros come these are pretty mild.


Mind this is only the simplest functions and thing can already go wild if you apply classic bad C++ coding practices, like cascade inheritance or god object. Add to that, you will (oh yes, you will, at least once) make type errors with macros, and you will fail to maintain all the class constructors and virtual functions.


I'd miss the STL more than anything. It's so much nicer than any of the remotely comparable C data structure + algorithm libraries. That plus RAII are enough to keep me on the C++ side.


Alternatively, the STL is so bloated and there are so many ways to mess up RAII that it's enough to keep me on the C side. Where I sell C shells.


The STL is actually pretty lean compared to the standard libraries that ship with most popular programming languages these days and if you leave the iostream stuff out it's fast and doesn't take up much space in the binary. I've used it with great results on iOS devices. My first step in creating any new class is subclassing a no-copy parent, which in my experience eliminates most of the nasty gotchas with accidental copies. I have yet to get any RAII weirdness.

I've considered reverting to plain C to make it easier to interface with other languages like pure ObjC and now Swift but when I think about how much extra work this is going to entail for absolutely zero benefit to my users I always give up the idea.


My first step in creating any new class is subclassing a no-copy parent

That's exactly why, when presented with a choice between C or C++, I'll choose C every time.

First, because it's often inexperience with other paradigms that forces programmers into an "everything must be an object" mindset. Second, because the fact that you need to learn a gargantuan amount of trivia to use C++ inheritance non-dangerously is a sign of underlying derangement. Third, because through experience I've learned that C is far less scary once you embrace standard patterns for accomplishing various tasks. The total linecount isn't significantly increased by using C over C++. The codebase complexity isn't increased.

What I like about C is that it gives you a set of inalienable commandments: thou shalt not go completely nuts with {inheritance, template metaprogramming, flavor du jour}, because you can't. In the hands of an experienced programmer, C gives you more reliability than C++ precisely because there are fewer gotchas. The dangers are straightforward: free memory after you use it; have a single place that a pointer is "owned"; check your lengths before copying between buffers.


I actually very rarely create class hierarchies in C++. I do, however, define and implement interfaces and this is a simple, no-brainer technique that eliminates a whole class of gotchas when I do it.

The total linecount isn't significantly increased by using C over C++. The codebase complexity isn't increased.

This I can't agree with at all. If I had to rewrite my current codebase in C it would be substantially larger and buggier and much less flexible. I know because I've tried this experiment already. This is even more the case with the C++11 syntax enhancements, which reduce the verbosity of C++ a lot.

My only real complaint with C++ is that it lacks a proper ABI so I have to wrap it in C if I want to use it from another language. This wasn't a big deal when I could rely on Obj-C++ but Apple's new Swift language has thrown a bit of a wrench in this scheme.


This is even more the case with the C++11 syntax enhancements, which reduce the verbosity of C++ a lot.

Maybe true. I bailed from the C++ world before C++11 became pervasive. But if you use C++11 you risk leaving VS2010 users (and below) in a situation where they can't use your code at all: http://blogs.msdn.com/b/vcblog/archive/2010/04/06/c-0x-core-...

And C++14? No idea what version of VS supports it. But using C++14 will definitely mess with people who have older compilers. And those people don't always have the luxury of just buying the latest version of VS.

Who cares about Windows? Well, anyone who's into the open source movement should be sympathetic to people who are forced to use a certain operating system but still want to get into programming. The spark for people's desire to become programmers often starts by wanting to customize their environment. That leads them to shell scripting, which is a stepping off point into more advanced programming.

The main point is simply that the C++ ecosystem has so many "gotchas" and timesinks that when forced to choose between C++ and C, an experienced programmer will save time with C, mainly because their years-old patterns will work regardless of what environment they're in. There are still some gotchas, of course; you can't use unix signals and expect them to be cross-platform. But it's far more straightforward than trying to get your codebase compiling on five different compilers.

Of course, choosing Python or some higher level language is almost always the best cost/benefit tradeoff.


C++ standards compliance is better now than its ever been. You can't have a nice modern language and expect to support a four-year old IDE too. C++14 is mostly a minor refinement of C++11. You get a much nicer language already in C++11 that you can use pretty freely on modern platforms.

Sure, use the highest level language you can afford to use. But I can't agree that experienced programmers will in general choose C or be more productive in it. The counter-examples are almost too numerous to even know where to begin. Surely the people behind Photoshop, Chrome, Renderman and Cubase etc. are aware of C and made a conscious decision not to use it.


If you set your own standards based on what everyone else is doing, you'll never hit the high notes.

When you're a single programmer, you shouldn't look at what large groups of people are doing. Large groups often have no idea what they're doing, too, so that mindset is unproductive in general. Many of the reasons are political, not technical: suggesting that everyone be forced to program in Python to the exclusion of C++ denies your company the expertise of all C++ programmers. For some industries, like Renderman's or Photoshop's, that would be suicide.

There are many reasons Tarsnap is written in C and not C++. Colin was aware of C++, yet chose not to use it. If one of the smartest and most experienced programmers choose not to do something, it's worth understanding why. Perhaps they were avoiding pitfalls that you may be in danger of falling into.

On the other hand, if Colin were forced to program in C++, I'm sure it would be wonderful C++. So the point of C vs C++ may be moot anyway. What matters is that a programmer is experienced and competent, not necessarily what tools they're forced to use.


I choose C++ precisely because I am a single programmer. I can't afford to waste any time writing code that doesn't translate to a user feature. I write a lot less boilerplate and spend less time chasing bugs using C++ than I would in C.

If you're happy coding in C then by all means continue. I'm just a little tired of all the C++ critics that insist that only naive or inexperienced programmers use it and they'd all be equally productive if they'd just man up and use C for a while.

Down votes are not coming from me, by the way.


>>I'm just a little tired of all the C++ critics that insist that only naive or inexperienced programmers use it and they'd all be equally productive if they'd just man up and use C for a while.

I'm not sure where you run into all those C++ critics that prefer C. Programmers that like to write C seem pretty rare to me. The criticism flows both ways: for example the C++ FAQ (http://isocpp.org/wiki/faq) labels every feature that's in C primitive, dangerous, and obsolete. I don't see C++ programmers as naive and inexperienced at all. The biggest problem with C++ is how complex and difficult it is. It might have been considered friendly to newbies at one time, but nowadays I'd be surprised to hear that an inexperienced programmer was using C++. These days it's associated with native code and high performance (C is either lumped in or ignored).


C++ critics that insist that only naive or inexperienced programmers use it and they'd all be equally productive if they'd just man up and use C for a while.

I would never say such a thing, because I don't believe it.

Who cares about downvotes? Our conversation was fun. Thank you for it.


if Colin were forced to program in C++, I'm sure it would be wonderful C++

I have yet to be convinced that such a thing exists.

If it does exist, I've never seen it.


Your argument sucks because by appealing to authority of an active HN member, any retort is going to involve criticizing an active HN member who's not party to the conversation.


Heh, now there's an aspect I'd never considered: maybe HN has become the kind of place where people are afraid to say true things? I don't think so, though. At least, not yet. If something is true, it's usually met favorably. Especially critiques. Speaking your mind (tactfully) is one of the most important aspects of a community, otherwise it's merely an echo chamber.


Blaming the hypothetical people that one might imagine would look on the replier badly is not adequate justification for putting the replier in that position.


> Who cares about Windows? Well, anyone who's into the open source movement should be sympathetic to people who are forced to use a certain operating system but still want to get into programming.

But C++ is also much nicer to use on Windows than C.


> . But if you use C++11 you risk leaving VS2010 users (and below) in a situation where they can't use your code at all

And embedded developers! Don't forget us.

C++2003 if we're lucky.


>>I actually very rarely create class hierarchies in C++.

The book I learned C++ from must have weighed 5 pounds, and about 4 of them were devoted to inheritance. I assumed that inheritance was the central point of OOP. I never quite finished that C++ book; the details became overwhelmingly tedious, and I'd already learned to write programs. When the Gang of Four book came out, and in its opening pages declared that inheritance was a bad practice, and you should prefer composition wherever possible, I kind of laughed, thinking it had finally dawned on people that this was a bad idea, and OOP would go away soon. I could not have been more wrong about that.

I still don't quite get how a person can be for OOP and profess a dislike for class inheritance; or believe software engineering metrics that consider things like call-tree depth and class counts indicators of excessive complexity and still believe objects are the right model. It seems like all the features of OOP are tied up with inheritance, and all of the recommended practices around classes and objects imply convoluted code paths and architectural complexity by their very nature. OOP seems to thrive on contradictions.


Deep complicated inheritance hierarchies are usually misdesigned. OOP is just run-time polymorphism and you don't need anything besides abstract base classes for that. There is nothing contradictory about that GoF stance.


Deep, complicated inheritance hierarchies loaded with virtual functions is among my least favorite kinds of code to have to debug.


You can easily create interface vtables in C. These vtable (ptrs) don't have to be put into the objects themselves, which is a historic mistake that got thrown into C++ and other OO languages. The vtables can be passed as arguments to any operation, making them closer in power to type-classes than OO interfaces (i.e: much more powerful).


Linus Torvalds has written quite eloquently in defense of using exclusively C in the kernel, pointing out some brilliant insights. Of course, the kernel is his at the end of the day, so he doesn't really have to be persuasive and there's a lot of colorful language mixed in to those forum posts, too, which turns a lot of people off and prevents them from hearing the brilliance. But you could hardly pick a harder and more mission-critical project than the kernel, and the result speaks for itself.

Most projects are not the kernel, and for most normal-size projects, you'll probably get better results by picking a language you are experienced with and familiar with, rather than one that's in some sense universally optimal, but you have little experience in. But to sum up the advantage of C: C is for when you don't want any surprises. It's a very un-surprising language.


> But to sum up the advantage of C: C is for when you don't want any surprises. It's a very un-surprising language.

Actually, judging by the quantity of unspecified/undefined/implementation-defined behaviors in the C spec, I'd say C is full of surprises.


I've seen lists of those, and they are pretty esoteric. I don't think I've ever stepped on one accidentally.


How about the problem that the sizes of the basic types aren't exactly specified. All that C requires is that: char < short < int < long < long long and that sizeof(char) >= 8, sizeof(short) >= 16, sizeof(int) >= 16, sizeof(long) >= 32, sizeof(long long) >= 64 (from Wikipedia). The fact that int is allowed to be 16 bits, 32 bits, 64 bits or almost anything else is IMHO very nasty and has produced quite a few problems.


That is a problem, but doesn't C++ have the same problem?

The situation was better before 64-bit became popular, when int == long == 32 bits on any system that mattered (when 16-bit gave way to 32-bits, you couldn't be sorry about that, it was a relief). Somehow the transition to 64 bits got screwed up, and you can hardly trust the basic integer types anymore. I have started using the new stdint.h types wherever size is likely to be an issue.


> That is a problem, but doesn't C++ have the same problem?

It does, but that wasn't the point. I wasn't defending C++.


I guess I don't know what your point was.


That C isn't predictable or well-specified, which is a real problem when writing portable or secure code ("oh shit" moments in C code don't just give programmers headaches, but have caused tons of vulnerabilities).


Not predictable or well-specified in comparison to what? Buffer overflows are not caused by the language. They are a well-known risk of developing in native code. Well-known risks are not surprises.

Part of being unsurprising is being one of the oldest and most popular programming languages. There's no excuse for being surprised by what's well known.


In comparison to Java, for example. Java specifies integer and float semantics exactly, including what happens for things like over/underflow and division by zero. C leaves too much to be decided by the compiler writer or ABI.

Buffer overflows aren't the only problem C has. For an interesting discussion and examples of bad behavior that C allows, please take a look at [1] (especially part 2 of that series) and [2] (yes, some of these are compiler shenanigans; the problem is that the C standard allows the compiler to go crazy).

1 - http://blog.llvm.org/2011/05/what-every-c-programmer-should-...

2 - http://blog.regehr.org/archives/213


That's very interesting! Would you link to some of Linus's writings? Alternatively, I could try to search for them myself if you point out some keywords to google for. Did you have any particular articles in mind?


Sure. Here's one I bookmarked a long time ago: http://www.realworldtech.com/forum/?threadid=104299&curposti...


The STL has huge mistakes like the completely useless "std::list".

It also does a whole lot of unnecessary dynamic allocations due to the non-intrusive style used for all of its containers.

I think the STL might be overhyped.


It would help if you could point me to something that is better than STL (in performance and ease of use) and addresses the full scope of STL. I have asked this a few times, but all I have got so far is cricket chirps or pointers to worse bloatware. Not claiming that such a thing does not exist, rather would be happy to give such a thing a try. It would also lend more heft to your comment.


Any library that addresses exactly the same use case as STL is going to have the same limitations as STL. Everything is a trade-off. I think you can probably assume that STL does about as good a job as any library would, given identical trade-offs. Note that the actual implementations will vary by platform and compiler.


The STL is an arbitrary collection of libraries. For any specific library within it, I might be able to.

For example, the Linux kernel's list.h is far superior to std::list.


95% of my use cases are satisfied by std::vector and std::map. Neither one has ever even shown up as a tiny blip in my performance traces, even in debug builds. If you really really need intrusive containers you can get them from boost.

Like anything in decades of heavy commercial use it has some warts but at least C++ gives you the control you need to write fast code at a reasonable level of abstraction.


I wasn't dissing C++ here (though I do believe C++ has quite a few downfalls..), just the STL.

std::vector is completely reasonable implementation for a dynamic vector.

std::map is somewhat unreasonable, because its non-intrusiveness requires dynamic allocations, more indirections, and more expensive deletions.

std::list is useless, so when you do want linked lists, you end up using the wrong data structure, because list is out of the lexicon.


Aka as "lots of hacks using non standard C, while forcing the developer to do the work of the compiler".


Yon mean "non idiomatic", right? I don't think he used anything non standard.


The max macro in Section 4 is using two separate GCC extensions: typeof and statements in expressions.


Yes, but sometimes for whatever reason C is all you have. And then tricks like these just might push down the complexity far enough to give you an edge. (Do it wrong and you'll lose a lot of hair.)


In 2014 I fail to see any scenario besides *BSD and GNU/Linux kernels, where C is available and C++ is not.


That's a limit in you, not in the scenarios.

Plenty of environments rule out C++ by policy imposed from above. Not all limitations are technical in nature (or even informed).

And there are plenty of technical ones as well (such as: predictability).


Embedded development...


I doubt that there are many embedded environments where you can't get C++ these days.


I always used a mix of C++ or/and pure Assembly.


I couldn't care less about trying to reimplement classes in C — structs and functions will do just fine thank you very much. What about something actually useful, like RAII to simplify memory management?


RAII

Please, yes. It happens I just spent the morning writing some C with files, views of those files etc, and I kept on whishing there was RAII, instead of having to build flow around the fact each of the operations might fail.

Is there a clean way to implement something like this in C?

I couldn't care less about trying to reimplement classes

indeed - the premise the OP starts with, i.e. 'here's the simplest class: BANG two subclasses' is also wrong. That is inheritance, not just 'the simplest class' as that wouldn't have anything to do with inheritcance.


I remember something implemented as GCC extension (the cleanup variable attribute) but I never used it so I can't judge if it's really what are you searching for.


Gcc cleanup extension works very well for RAII, I used it extensively to write a simple profiler for a video game project (just add 'PROFILE' on top of a function to have it automatically profiled). The only problem is that this is not supported by MSVC.


It is supported by clang though. Maybe you could use clang-cl to get it into msvc no?


> Is there a clean way to implement something like this in C?

    __attribute__((cleanup(…)))


I really like talloc as a means of simplifying memory management. It's not, RAII, though.


Perhaps you might be interested in Rust?


This is a nice article for anyone who wants to understand typical implementation of basic C++ features but in the end I'd say it makes the case for actually using C++ instead of reimplementing it in C.

If you do go the OOP-C route, one thing that's nice is that you can compose objects of different super types. In C++ an object belongs to one class of a hierarchy but in OOP-C it's conceivable that the vtable dispatches to a different mixt of virtual functions per object.

Also, nice trick with the #define T/#include __FILE__. Hadn't seen that before.


I think this proofs Scott Meyers point about the most important feature we have in C++: the destructor.


I've always liked to keep in mind that C++ was developed as an extension to C ( http://en.wikipedia.org/wiki/Cfront ), so most of the constructs that it has can be directly mapped to C --- I think the only exception is... exceptions, although there's probably a way to do it using setjmp/longjmp too.

Personally I prefer C because of all the added flexibility it allows, but I can definitely see the value of a lot of the features added by C++ - C programmers were using structures and function pointers before, now they can use classes. RAII - a nice benefit of the semantics of constructors and destructors - is a more implicit, easier way of doing the same thing manually by calling the appropriate functions. Templates make it easy to generate a lot of otherwise very similarly structured code. Operator overloading can replace function calls and make some expressions look clearer.

However, the biggest disadvantage of all these features is that they add complexity and cognitive overhead to understanding the code - abstractions are only truly useful to those who know what the abstractions are of. That's why I believe that anyone who wants to learn C++ should already have strong knowledge of C (including structures, pointers, and memory allocation), and preferably know some Asm; then the transition to using the features of C++ feel straightforward and natural, without the "I don't know how it works, it's all magic" feeling to them. It's for this same reason that I recommend reading through the code of the STL - a good one to start with is std::vector.


>>I think the only exception is... exceptions, although there's probably a way to do it using setjmp/longjmp too.

I'm pretty sure that C++ exceptions could be simulated that way.

>>Templates make it easy to generate a lot of otherwise very similarly structured code

Templates are a mixed bag. There are a lot of things that look like they should be possible with templates, but once you start trying to implement them, it suddenly becomes much more difficult. Most of the practical value of templates is in getting around data type limitations and in inlining, IMO. Luckily, C has simpler data types than C++, so there is less need to climb over barriers, but templates do provide some value over C in this respect. The value with respect to inlining may be decreasing as C compilers become more sophisticated, but I'm not certain. std::sort() is said to be faster than qsort(). I've wondered if there is any way to coax a C compiler into inlining the sort routine, callback and all, but I haven't tried it yet.


> I'm pretty sure that C++ exceptions could be simulated that way.

Indeed they can, may I introduce you to the preprocessor/macro extravaganza that is libextc: https://github.com/jspahrsummers/libextc/blob/master/src/exc...

I used it for a bit mostly to learn the chicanery of the madness. But I'm not a huge exception fan in general it just doesn't fit C well in my opinion.


I've never seen much value in exceptions. For that matter, I've never had much interest in using longjmp and setjmp. It's possible that I tried them out at one point just to see them work. But I've never come up with a use for them.


Well if you try using setjmp/longjmp and then introduce threads with this stuff, I think you'll quickly realize where this whole rigamarole breaks down.

I gave it a quick try but honestly its simpler to just use straightforward C.


I admire your persistence and tenacity in getting as far as you did with that rigamarole. I'll take your word for it that it that it ends badly. :)


Heh thanks, it was more along the lines of: well i've never tried to get set/longjmp to work with threads, how hard can it be?

Short answer, harder than you'd initially think. So many edge cases, the horror.


It seems like someone must have done it, if doing it is at all worthwhile...


>I've wondered if there is any way to coax a C compiler into inlining the sort routine, callback and all, but I haven't tried it yet.

And how is the compiler supposed to inline the callback in qsort() when all it has is a pointer that will be provided only at runtime ? With JIT yes that would be possible. This requires a runtime optimization solution, not a compile time. This is also the reason why templates come so handy, sans the error messages (although GCC has improved by leagues, now to the point I find GCC's error messages easier to debug STL code with than Clang's). The error message scenario would a be a lot better once they get concepts sorted out.


I don't have stats, but I would think that the comparison function's definition typically is available at compile time.

Also, if the compiler gets the qsort prototype by including it from the system header <stdlib.h>, I think the compiler may assume that it is the standard qsort function. So, it could emit a custom qsort function that inlines the comparison function.


>I don't have stats, but I would think that the comparison function's definition typically is available at compile time.

The comparison function usually will be. The qsort function generally won't be available.

>Also, if the compiler gets the qsort prototype by including it from the system header <stdlib.h>, I think the compiler may assume that it is the standard qsort function. So, it could emit a custom qsort function that inlines the comparison function.

It could do something like that, but gcc doesn't (https://gcc.gnu.org/onlinedocs/gcc-4.9.0/gcc/Other-Builtins....).

If you look at the kinds of API functions implemented as builtins, they are generally simple.


It's probably impossible with qsort. I was wondering, if both the sort routine and the callback were declared static, would gcc be clever enough to inline both, eliminating the function pointer? It seems like it should be possible in principle.


Inline qsort, then inline the callback.


> There are a lot of things that look like they should be possible with templates, but once you start trying to implement them, it suddenly becomes much more difficult.

No it doesn't.


The problem with many of these OO in C workarounds is how well they work at scale. For small projects, they're fine. But in larger projects, the compromises in the design begin to show up and require additional patching. This same problem--increasingly messy code to emulate C++ features--led to the abandonment of cfront and the development of true C++ compilers.


The scale argument is dogma. We already know huge, successful code bases exist in C and many employ similar techniques to this. (These are pretty mild tricks.) Additionally, the scaling argument is often used to belittle other languages like Python, Ruby, Lua, JavaScript, etc. All propaganda BS.


I have written related article

http://www.avabodh.com/cxxin/cxx.html


I could probably live with most of this, but the macros make me want to gouge my eyes out. C macros just have too many issues


It's fun to know how we implement these stuffs in C but not fun enough to use them :)


Three other ways to do OOP in C

http://www6.uniovi.es/cscene/CS1/CS1-02.html


I hate when people try to do this, it makes the code almost unreadable, if you want to use classes, use C++.


Basic template: how do you single-step through a multiple-statement macro? Advanced template: where's specialization? Also, where's RAII?

Nothing to see there, move on.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: