Name: Anonymous 2010-04-07 17:09
Hi folks,
After getting frustrated that I couldn't easily accomplish what I wanted to in C, such as growable type-safe arrays and inheritance/polymorphism, I recently partially converted my ~10ksloc game project to C++. I didn't convert it all at once; I just made it all compile as C++, and gradually converted it as I worked on new stuff. About half of it is OOP/templates, and the other half is still pure C99 which compiles as C++. Notice I said 'easily'; I did write a type-safe vector template as a macro which you explicitly instantiate, and I did have a reasonably complex inheritance tree by writing vtables manually. These were just a pain in the ass to maintain.
Now I am somewhat regretting this decision. I'm realizing that these things that pushed me to convert it to C++, I shouldn't really have been doing them in the first place. Growable vectors (such as std::vector) are a terrible idea. Dynamic memory allocation is just a bad idea in general. You can't use these because an allocation might fail at any moment. Whether you throw an exception or you correctly handle and propagate a memory error via return values, it doesn't matter; you can't usefully recover in the middle of an operation. The only sane way is to pre-allocate everything you need at load time. If you do this properly, growable vectors are useless.
And complex inheritance trees are just bad. I should instead have been doing pure polymorphism, without inheritance. There's still a bit of overhead in writing a vtable, but there's no complexity. I spent so much time figuring out what methods go in which object, and shuffling them around from base classes to subclasses and back again... I should have learned to separate my algorithms from the objects they apply to.
I'm also finding that all the supposed advantages of C++ are useless or inferior to C. C++ encapsulation and header file management is even worse than C, because I have to expose my structure and private methods causing endless rebuild cycles. Creating callbacks is WAY more complicated than it should be (have to define an interface and then implement it instead of just handing over a function and struct pointer.) What is the point of all this?
The only feature I see myself using right now that isn't completely useless is overloading on types. Namespacing all my functions manually is a pain, and the argument that it helps readability doesn't really fly.
Lately I've been contemplating creating my own toy language, which is basically C except it doesn't use header files and allows overloading on types. There are tons of quicky compiler tutorials out there using tools like Flex+Bison; I am sure I could create a C99 parser which additionally allows overloading on argument types, and simply outputs C99 with header files and fully namespaced functions (or just calls LLVM directly).
Ironically this sounds a lot like Go, except I find Go has made a whole lot of bad decisions: garbage collection is a horrible idea for a systems/game language, enforcing encapsulation / exporting functions via naming conventions (uppercase wtf??), whitespace is starting to matter (notice what they're doing with removing semicolons, and all the bullshit wierdo special cases, like where you have to leave an extra trailing comma if you break up your argument list in different lines).
Would a language like this interest anyone? Should I just keep my project the way it is, half C++ and half C? What to do?
After getting frustrated that I couldn't easily accomplish what I wanted to in C, such as growable type-safe arrays and inheritance/polymorphism, I recently partially converted my ~10ksloc game project to C++. I didn't convert it all at once; I just made it all compile as C++, and gradually converted it as I worked on new stuff. About half of it is OOP/templates, and the other half is still pure C99 which compiles as C++. Notice I said 'easily'; I did write a type-safe vector template as a macro which you explicitly instantiate, and I did have a reasonably complex inheritance tree by writing vtables manually. These were just a pain in the ass to maintain.
Now I am somewhat regretting this decision. I'm realizing that these things that pushed me to convert it to C++, I shouldn't really have been doing them in the first place. Growable vectors (such as std::vector) are a terrible idea. Dynamic memory allocation is just a bad idea in general. You can't use these because an allocation might fail at any moment. Whether you throw an exception or you correctly handle and propagate a memory error via return values, it doesn't matter; you can't usefully recover in the middle of an operation. The only sane way is to pre-allocate everything you need at load time. If you do this properly, growable vectors are useless.
And complex inheritance trees are just bad. I should instead have been doing pure polymorphism, without inheritance. There's still a bit of overhead in writing a vtable, but there's no complexity. I spent so much time figuring out what methods go in which object, and shuffling them around from base classes to subclasses and back again... I should have learned to separate my algorithms from the objects they apply to.
I'm also finding that all the supposed advantages of C++ are useless or inferior to C. C++ encapsulation and header file management is even worse than C, because I have to expose my structure and private methods causing endless rebuild cycles. Creating callbacks is WAY more complicated than it should be (have to define an interface and then implement it instead of just handing over a function and struct pointer.) What is the point of all this?
The only feature I see myself using right now that isn't completely useless is overloading on types. Namespacing all my functions manually is a pain, and the argument that it helps readability doesn't really fly.
Lately I've been contemplating creating my own toy language, which is basically C except it doesn't use header files and allows overloading on types. There are tons of quicky compiler tutorials out there using tools like Flex+Bison; I am sure I could create a C99 parser which additionally allows overloading on argument types, and simply outputs C99 with header files and fully namespaced functions (or just calls LLVM directly).
Ironically this sounds a lot like Go, except I find Go has made a whole lot of bad decisions: garbage collection is a horrible idea for a systems/game language, enforcing encapsulation / exporting functions via naming conventions (uppercase wtf??), whitespace is starting to matter (notice what they're doing with removing semicolons, and all the bullshit wierdo special cases, like where you have to leave an extra trailing comma if you break up your argument list in different lines).
Would a language like this interest anyone? Should I just keep my project the way it is, half C++ and half C? What to do?