C++ As a Better C

There's this old joke about C++...

> Developer's Insight, December 1991 (approx version)

> How to Shoot Yourself In the Foot (in various programming languages)

> C++
>   You accidently create a dozen instances of yourself and shoot them all in the foot.
>   Providing emergency medical assistance is impossible since you can't tell which are
>   bitwise copies and which are just pointing at others and saying "That's me, over there."

While perhaps true in '91, I contend that the situation has gotten even worse since then.

Not that C++ isn't a massive improvement over C, but its features give rise to a list of drawbacks:

- It's easy to write unintentionally obfuscated code.
- It's easy to write code that happens to work, but accidentally passes objects by value rather than reference, and then unintentionally copies and deletes them over and over.
- It's easy to lose track of whether an instance of an object is a copy of another object, or just a reference to it.
- It's easy for a few lines of code to balloon into an unexpectedly large binary because of agressive inlining.
- It's easy to get confused about which of a dozen, subtly different subclasses, with long names, containing obtuse abbreviations, to use.
- It's easy to get locked into an API because it defines it's own types and doesn't provide any good way to convert them to anything else.

Or, at least, I've been frustrated by each of those problems at one time or another, over the years.

The standard API's for many other high level languages seem to just implement paradigms established by C in an object oriented manner. Rudiments takes this approach too, in effect, using "C++ as a better C".

- C types (and bool) are used throughout.
- Primitive types are passed by value, arrays and objects are passed by reference.
- Templates are only used in data structures.
- Operators are not overloaded to provide unintuitive functionality.
- Class heirarchies are shallow, with a minimum of multiple inheritance and no virtual inheritance.
- Rather than being subclassed, classes usually have attributes or options.
- File I/O follows the open(), read(), write(), close() paradigm.
- Network I/O follows the connect(), read(), write(), close() paradigm.
- Standard I/O follows the read(), write(), printf() paradigm.

Further, rather than abstracting the entire set of Posix and Windows errors into hundreds of individual exceptions, Rudiments' methods throw no exceptions and generally return true on success and false on failure. Since most methods just wrap C functions, errno is set when a method fails, and the error class (which wraps errno) can be used to get the specific error number and string.

As such, Rudiments can be compiled with the -fno-exceptions flag to conserve space on resource-limited platforms.

Rudiments doesn't use any dynamic_cast operations internally either, so if your applications don't do any run-time type-checking of Rudiments classes, then Rudiments can also be compiled with the -fno-rtti flag to further conserve space on resource-limited platforms.