C++ vs. D , Ada and Eiffel (horrible error messages with templates) - c++

One of the problems of C++ are horrible error messages that we are getting from code which intensively uses templates and template metaprogramming. The concepts are designed to solve this problem, but unfortunately they will not be in the next standard.
I'm wondering, is this problem common for all languages, which are supporting generic programming? Or something is wrong with C++ templates?
Unfortunately I don't know any other language, that supports generic programming (Java and C# generics are too simplified and not as powerful as C++ templates).
So I'm asking you guys: are D,Ada,Eiffel templates (generics) producing such ugly error messages too? And Is it possible to have language with powerful generic programming paradigm, but without ugly error messages? And if yes, how these languages are solving this problem ?
Edit: for downvoters. I really love C++ and templates. I'm not saying that templates are bad. Actually I'm a big fan of generic programming and template metaprogramming. I'm just asking why I'm getting such ugly error messages from compilers.

In general I found Ada compiler error messages for generics really not significantly more difficult to read than any other Ada compiler error messages.
C++ template error messages, on the other hand, are notorious for being error novels. The main difference I think is the way C++ does template instantiation. The thing is, C++ templates are much more flexible than Ada generics. It is so flexible, it is almost like a macro preprocessor. The clever folks in Boost have used this to implement things like lambdas and even whole other languages.
Because of that flexibility, the entire template hierarchy basically has to be compiled anew every time its particular permutation of template parameters is first encountered. Thus issues that resolve down to incompatibilities several layers down a API end up being presented to the poor API client to decipher.
In Ada, Generics are actually strongly typed, and provide full information hiding to the client, just like normal packages and subroutines do. So if you do get an error message, it is typically just referencing the one generic you are trying to instatiate, not the entire hierarchy used to implement it.
So yes, C++ template error messages are way worse than Ada's.
Now debugging is a different story entirely...

The problem, at heart, is that error recovery is difficult, whatever the context.
And when you factor in C and C++ horrid grammars, you can only wonder that error messages are not worse than that! I am afraid that the C grammar has been designed by people who didn't have a clue about the essential properties of a grammar, one of them being that the less reliance on the context the better and the other being that you should strive to make it as unambiguous as possible.
Let us illustrate a common error: forgetting a semi-colon.
struct CType {
int a;
char b;
}
foo
bar() { /**/ }
Okay so this is wrong, where should the missing semi-colon go ? Well unfortunately it's ambiguous, it can go either before or after foo because:
C considers it normal to declare a variable in stride after defining a struct
C considers it normal not to specify a return type for a function (in which case it defaults to int)
If we reason about, we could see that:
if foo names a type, then it belongs to the function declaration
if not, it probably denotes a variable... unless of course we made a typo and it was meant to be written fool, which happens to be a type :/
As you can see, error recovery is downright difficult, because we need to infer what the writer meant, and the grammar is far from being receptive. It is not impossible though, and most errors can indeed be diagnosed more or less correctly, and even recovered from... it just takes considerable effort.
It seems that people working on gcc are more interested in producing fast code (and I mean fast, search for the latest benchmarks on gcc 4.6) and adding interesting features (gcc already implement most - if not all - of C++0x) than producing easy to read error messages. Can you blame them ? I can't.
Fortunately there are people who think that accurate error reporting and good error recovery are a very worthy goal, and some of those have been working on CLang for quite a bit, and they are continuing to do so.
Some nice features, off the top of my head:
Terse but complete error messages, which include the source ranges to expose exactly where the error emanated from
Fix-It notes when it's obvious what was meant
In which case the compiler parses the rest of the file as if the fix had been there already, instead of spewing lines upon lines of gibberish
(recent) avoid including the include stack for notes, to cut out on the cruft
(recent) trying only to expose the template parameter types that the developper actually wrote, and preserving typedefs (thus talking about std::vector<Name> instead of std::vector<std::basic_string<char, std::allocator<char>>, std::allocator<std::basic_string<char, std::allocator<char>> > which makes all the difference)
(recent) recovering correctly in case of a missing template in case it's missing in a call to a template method from within another template method
But each of those has required several hours to days of work.
They certainly didn't come for free.
Now, concepts should have (normally) made our lives easier. But they were mostly untested and so it was deemed preferable to remove them from the draft. I must say I am glad for this. Given C++ relative inertia, it's better not to include features that haven't been thoroughly revised, and the concept maps didn't really thrilled me. Neither did they thrilled Bjarne or Herb it seems, as they said that they would be rethinking Concepts from scratch for the next standard.

The article Generic Programming outlines many of the pros and cons of generics in several languages, including Ada in particular. Although lacking template specialization, all Ada generic instances are "equivalent to the instance declaration…immediately followed by the instance body". As a practical matter, error messages tend to occur at compile-time, and they typically represent familiar violations of type-safety.

D has two features to improve the quality of template error messages: Constraints and static assert.
// Use constraints to only allow a function to operate on random access
// ranges as defined in std.range. If something that doesn't satisfy this
// is passed, the compiler will error before even trying to instantiate
// fun().
void fun(R)(R range) if(isRandomAccessRange!(R)) {
// Do stuff.
}
// Use static assert to check a high level invariant. If
// the predicate is false, the error message will be
// printed and compilation will stop before a screen
// worth of more confusing errors are encountered.
// This function takes any number of ranges to merge sort
// and the same number of temporary buffers to merge into.
void mergeSort(R...)(R ranges) {
static assert(R.length % 2 == 0,
"Must have equal number of ranges to be sorted and temporary buffers.");
static assert(allSatisfy!(isRandomAccessRange, R),
"All arguments to mergeSort must be random access ranges.");
// Implementation
}

Eiffel has the best of all error messages because it is has the best of all template systems. It is fully integrated into the language and works well because it is the only language which is using covarianz in arguments.
Therefore it is much more then a simple compiler copy and paste. Unfortunately explaining the difference in a few lines is impossible. Just go and have a look at EiffelStudio.

There are some efforts to improve the error messages. Clang, for example, has put quite a lot of emphasis on generating more easily readable compiler error messages. I've only been using it for a short while, but my experience of it so far has been quite positive compared to GCC's equivalent errors.

Related

Should I really massively introduce the explicit keyword?

When I used the (recently released) Cppcheck 1.69 on my code1, it showed a whole lot of messages where I expected none. Disabling noExplicitConstructor proved that all of them were of exactly this kind.
But I found that I'm not the only one with a lot of new Cppcheck messages, look at the results of the analysis of LibreOffice (which I'm allowed to show in public):
What would an experienced programmer do:
Suppress the check?
Massively introduce the explicit keyword?
1 This is of course not my code but code I have to work at work, it's legacy code: a mix of C and C++ in several (pre-)standard flavors (let's say C++98), and it's a pretty large code base.
I've been bitten in the past by performance hits introduced by implicit conversions as well as outright bugs. So I tend to always use explicit for all constructors that I do not want to participate in implicit conversions so that the compiler can help me catch my errors - and I then try to always also add a "// implicit intended" comment to the ctors where I explicitly intend for them to be used as converting ctors implicitly. I find that this helps me write more correct code with fewer surprises.
… So I'd say "yes, go add explicit" - in the long run you'll be glad you did - that's what I did when I first learned about it, and I'm glad I did.

Is there a general consensus in the C++ community on when exceptions should be used? [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 9 years ago.
I just spent a few hours reading through SO questions on the topic of when to use exceptions, and it seems like there are two camps with different point of views:
Use exceptions over error codes
Use error codes most of the time, and exceptions only when some catastrophic error occurs
Is this just a controversial topic with no widely accepted best practice?
As you can probably gather from the wealth of answers, there is certainly no consensus.
Semantically, exceptions and error provide the exact same functionality. Indeed they are identical in about all semantic aspects, and errors can be arbitrarily enriched much like exceptions (you don't have to use a simple code, you can use a real bundle of data!).
The only difference there is is their propagation methods:
errors have to be passed down manually
exceptions are propagated automatically
On the other hand:
the possibility of an error is perfectly documented in the signature
exceptions are silent on code inspection (read GotW #20: Code Complexity and cry) and hidden paths of execution make reasoning harder.
The very reason both solutions can appear clunky is simply that error checking is difficult. Indeed most of the code I am writing daily concerns error checking, whether technical or functional.
So what to do ?
Warning: demonstration ahead, jump over to the next section if you care only for an answer
I personally like to leverage the type system here. The typical example is the pointer-reference dichotomy: a pointer is like a reference that can be null (and reseated, but it does not matter here)
Therefore, instead of:
// Exceptions specifications are better not used in C++
// Those here are just to indicate the presence of exceptions
Object const& Container::search(Key const& key) const throw(NotFound);
I will tend to write:
Object const* Container::search(Key const& key) const;
Or better yet, using clever pointers:
Pointer<Object const> Container::search(Key const& key) const;
template <typename O>
O* Pointer<O>::operator->() const throw(Null);
template <typename O>
O& Pointer<O>::operator*() const throw(Null);
Here I find the use of exception superfluous for 2 reasons:
If we are searching for an object, then there not finding it is both a perfectly common occurrence and there is not much data to carry about: cause of error ? it is not there
The client does not necessarily consider it an error that it is not there, who am I to assume that I know her business better than she does ? Who am I to decide that there will never be a case where it won't be appropriate not to find what was asked for ?
I don't have a problem with exceptions per se, but they can make the code awkward, consider:
void noExceptions(Container const& c)
{
Pointer<Object const> o = c.search("my-item");
if (!o) {
o = c.search("my-other-item");
}
if (!o) { return; } // nothing to be done
// do something with o
}
And compare it with the "exception" case:
void exceptions(Container const& c)
{
Object const* p = 0;
try {
p = &c.search("my-item");
}
catch(NotFound const&) {
try {
p = &c.search("my-other-item");
}
catch(NotFound const&) {
return; // nothing to be done
}
}
// do something with p
}
In this case, the use of exceptions does not seem appropriate :/
On the other hand:
try {
print() << "My cute little baby " << baby.name() << " weighs " << baby.weight();
}
catch(Oupsie const&) {
// deal
}
is certainly more appealing than:
if (!print("My cute little baby ")) { /*deal*/ }
if (!print(baby.name())) { /*deal*/ }
if (!print(" weighs ")) { /*deal*/ }
if (!print(baby.weight())) { /*deal*/ }
What is the best then ?
It depends. Like all engineering problem there is no silver bullet, it's all about concessions.
So keep 2 things in mind:
Error reporting is part of the API
APIs should be designed with ease of use in mind
If you find yourself wondering whether to use an exception or not, just try to use your API. If there is no clear cut winner, it is just that: there is no ideal solution.
Oh, and do not hesitate to refactor your API when it becomes clear that the error reporting mechanism elected at the time of crafting it is no longer appropriate. Don't be ashamed: requirements change with time, so it is normal that the API change with them.
Personally I tend to use exceptions for unrecoverable errors only: I therefore have few try/catch in my code, only in the outermost levels, to accurately log the error (love stack frames) and log a dump of the BOM as well.
This is very similar (and indeed strongly influenced) by Haskell, the code there is seggregated in two clear cut parts: while any can throw exceptions, only the IO part (the extern one) may actually catch them. Therefore, the pure part must deal with error conditions with other ways in case they are "normal".
If, however, I am faced with a problem where using an exception makes the code easier to read and more natural (which is subjective) then I use an exception :)
I don't think this is a discussion which is exclusive to the C++ community, but here are two high-level guidelines which have helped me:
Throw exceptions only in exceptional circumstances. It sounds obvious, but many APIs get built with exceptions being thrown about 50% of the time they are called (and a boolean return status would have been more appropriate).
In your catch clauses, know when to consume exceptions, when to rethrow them as-is and when to throw a different type of exception instead. I can't give you a one-size-fits-all rule for this because it's so dependent on your application's needs, but if you take one thing away from this it should be that the silent consumption of an exception might be the worst thing your code could do. Each frame should have some knowledge of what the calling frame(s) expects when things go wrong.
Exceptions are easier to use than error codes, because they can be thrown by an deeply nested subroutine and intercepted only at the level where it can be handled.
Error codes need to be passed up the chain so every function that calls another has to pass the error code back to its callers.
An error code doesn't have any clear functional advantages over exceptions since an exception can bundle an error code within it. There may have been a time when error codes might be more efficient than exceptions, but I think the cost of the extra code and the difficulty in maintaining it outweighs any possible advantage there.
However, error codes exist in many applications because they are written in, or were ported from, a language that didn't have exceptions, so it makes sense to keep using a uniform approach to error handling.
No, there's no consensus, though.
Edit: As you can see, from the other answers, there's no consensus -- only schools of thought, principles of design, and plans of action. No plan is perfectly suited for every situation.
Even if there were a common consensus, it wouldn't mean it is valid. Your primary consideration here should be the implementation and performance costs. These are both real constraints on the project and the resulting program. In this respect, here are some things to consider.
At runtime, exceptions are more expensive to propagate than simple return values. This is usually the source of the in exceptional cases argument. If you are throwing a lot of exceptions all the time you are suffering a performance penalty. Don't take this to mean exceptions are slow, they are still implemented very efficiently, but nonetheless costlier than error codes.
Exceptions can carry more information than error codes. Something like the boost::exception library allows tagged information which can provide a wealth of useful information up the chain of the exception. Unlike a simple error code saying file not found an exception can carry the filename, the module that tried to load it, and of course the underlying error code. This type of information is very hard to propagate via error codes up the stack.
Error code propagation can be cumbersome at implementation time. Any function that doesn't want to deal with an error has to pass the value up higher. Quite often you'll find code that simply ignores the error since the programmer couldn't deal with it at the time, or he didn't want to refactor his function signatures to pass along the error.
Exception catch syntax is bulky. It is often far easier to check a return code in an if statement than having to write a catch block. If a function has to catch too many differing exceptions at different points, the meaning of the code will be lost in a sea of braces and try/catch clauses. Here is the likely root of the notion that if a function call can normally fail a return code is likely better than an exception.
Understanding clearly how exceptions work will help you in making a decision. There are performance considerations but for many projects this will be negligible. There are concerns about exception safety, you have to know where it is safe and unsafe to use exceptions. Error codes also have the same safety concerns if people start doing short returns from functions.
Understanding the background of your team can also help out; consider if you have two new C++ programmers, one from a C background and the other coming from Java. Some people are more comfortable with error codes, others with exceptions. How far you push either in each direction will impact your project and contribute to the overall quality.
In the end there is no clear answer. While there are some situations where one may clearly win over the other, it highly depends on the project. Look at your code and continue to refactor when appropriate. Sometimes you won't even have an option as to what you use. Other times it'll make no difference. It is highly project specific.
There is most certainly no consensus. At a high level, my mantra is that exceptions should be used in "exceptional cases" - that is, cases that are not a result of programmer error but of unpredictable conditions in the execution environment.
There are volumes of debate surrounding this issue. Depending on other practices in which you engage when writing programs - RAII for example - exceptions may become more or less idiomatically useful.
Exceptions are the only way to properly report errors from a constructor, so the choice is clear there. Throwing an exception forces the caller to catch it and handle it somehow. The alternative design of an empty constructor with an init() method returning an error code is error prone and can lead to objects with an unknown state.
The "C++ community" has factions, each of which has its own opinion about exceptions.
Where I work in the videogame industry, exceptions are forbidden in code that runs on a videogame system. This is because exceptions consume either CPU time OR memory, neither of which a videogame system has any to spare.
Also, in videogames there are few failure cases that warrant graceful recovery; If a videogame fails, human lives or property are not typically at stake.
I like Boost's Error and Exception Handling guidelines. Basically, use exceptions when stack unwinding is desirable. This is simple and unambiguous.
No consensus, but as the replies indicate, many people hold to the view to throw exceptinos only in exceptional circumstances. I don't much like that advice, because then the question becomes "what is an exceptional circumstance?". I prefer the following advice
A function must throw an exception if, and only if, the alternative would be failure to meet a post-condition (including all invariants as implicit post-conditions).
The implementation decision of whether to write throw in your code is then tied to the design decisions of the post-conditions for the function.
See C++ Coding Standards by Herb Sutter and Andrei Alexandrescu, items 70 (Distinguish between errors and non-errors) and 72 (Prefer to use exceptions to report errors).
I did not see this addressed in any other replies, but (as described in the "Effective Java" book) when doing OOP, a possiblity to skip throwing exceptions is to have a helper method in an object to "ask" whether the operation to be done is possible.
For example the hasNext() method on Iterator or Scanner which is usually called before calling the corresponding next*() method.

Expressions with no side effects in C++

See, what I don't get is, why should programs like the following be legal?
int main()
{
static const int i = 0;
i < i > i;
}
I mean, surely, nobody actually has any current programs that have expressions with no side effects in them, since that would be very pointless, and it would make parsing & compiling the language much easier. So why not just disallow them? What benefit does the language actually gain from allowing this kind of syntax?
Another example being like this:
int main() {
static const int i = 0;
int x = (i);
}
What is the actual benefit of such statements?
And things like the most vexing parse. Does anybody, ever, declare functions in the middle of other functions? I mean, we got rid of things like implicit function declaration, and things like that. Why not just get rid of them for C++0x?
Probably because banning then would make the specification more complex, which would make compilers more complex.
it would make parsing & compiling the
language much easier
I don't see how. Why is it easier to parse and compile i < i > i if you're required to issue a diagnostic, than it is to parse it if you're allowed to do anything you damn well please provided that the emitted code has no side-effects?
The Java compiler forbids unreachable code (as opposed to code with no effect), which is a mixed blessing for the programmer, and requires a little bit of extra work from the compiler than what a C++ compiler is actually required to do (basic block dependency analysis). Should C++ forbid unreachable code? Probably not. Even though C++ compilers certainly do enough optimization to identify unreachable basic blocks, in some cases they may do too much. Should if (foo) { ...} be an illegal unreachable block if foo is a false compile-time constant? What if it's not a compile-time constant, but the optimizer has figured out how to calculate the value, should it be legal and the compiler has to realise that the reason it's removing it is implementation-specific, so as not to give an error? More special cases.
nobody actually has any current
programs that have expressions with no
side effects in them
Loads. For example, if NDEBUG is true, then assert expands to a void expression with no effect. So that's yet more special cases needed in the compiler to permit some useless expressions, but not others.
The rationale, I believe, is that if it expanded to nothing then (a) compilers would end up throwing warnings for things like if (foo) assert(bar);, and (b) code like this would be legal in release but not in debug, which is just confusing:
assert(foo) // oops, forgot the semi-colon
foo.bar();
things like the most vexing parse
That's why it's called "vexing". It's a backward-compatibility issue really. If C++ now changed the meaning of those vexing parses, the meaning of existing code would change. Not much existing code, as you point out, but the C++ committee takes a fairly strong line on backward compatibility. If you want a language that changes every five minutes, use Perl ;-)
Anyway, it's too late now. Even if we had some great insight that the C++0x committee had missed, why some feature should be removed or incompatibly changed, they aren't going to break anything in the FCD unless the FCD is definitively in error.
Note that for all of your suggestions, any compiler could issue a warning for them (actually, I don't understand what your problem is with the second example, but certainly for useless expressions and for vexing parses in function bodies). If you're right that nobody does it deliberately, the warnings would cause no harm. If you're wrong that nobody does it deliberately, your stated case for removing them is incorrect. Warnings in popular compilers could pave the way for removing a feature, especially since the standard is authored largely by compiler-writers. The fact that we don't always get warnings for these things suggests to me that there's more to it than you think.
It's convenient sometimes to put useless statements into a program and compile it just to make sure they're legal - e.g. that the types involve can be resolved/matched etc.
Especially in generated code (macros as well as more elaborate external mechanisms, templates where Policies or types may introduce meaningless expansions in some no-op cases), having less special uncompilable cases to avoid keeps things simpler
There may be some temporarily commented code that removes the meaningful usage of a variable, but it could be a pain to have to similarly identify and comment all the variables that aren't used elsewhere.
While in your examples you show the variables being "int" immediately above the pointless usage, in practice the types may be much more complicated (e.g. operator<()) and whether the operations have side effects may even be unknown to the compiler (e.g. out-of-line functions), so any benefit's limited to simpler cases.
C++ needs a good reason to break backwards (and retained C) compatibility.
Why should doing nothing be treated as a special case? Furthermore, whilst the above cases are easy to spot, one could imagine far more complicated programs where it's not so easy to identify that there are no side effects.
As an iteration of the C++ standard, C++0x have to be backward compatible. Nobody can assert that the statements you wrote does not exist in some piece of critical software written/owned by, say, NASA or DoD.
Anyway regarding your very first example, the parser cannot assert that i is a static constant expression, and that i < i > i is a useless expression -- e.g. if i is a templated type, i < i > i is an "invalid variable declaration", not a "useless computation", and still not a parse error.
Maybe the operator was overloaded to have side effects like cout<<i; This is the reason why they cannot be removed now. On the other hand C# forbids non-assignment or method calls expresions to be used as statements and I believe this is a good thing as it makes the code more clear and semantically correct. However C# had the opportunity to forbid this from the very beginning which C++ does not.
Expressions with no side effects can turn up more often than you think in templated and macro code. If you've ever declared std::vector<int>, you've instantiated template code with no side effects. std::vector must destruct all its elements when releasing itself, in case you stored a class for type T. This requires, at some point, a statement similar to ptr->~T(); to invoke the destructor. int has no destructor though, so the call has no side effects and will be removed entirely by the optimizer. It's also likely it will be inside a loop, then the entire loop has no side effects, so the entire loop is removed by the optimizer.
So if you disallowed expressions with no side effects, std::vector<int> wouldn't work, for one.
Another common case is assert(a == b). In release builds you want these asserts to disappear - but you can't re-define them as an empty macro, otherwise statements like if (x) assert(a == b); suddenly put the next statement in to the if statement - a disaster! In this case assert(x) can be redefined as ((void)0), which is a statement that has no side effects. Now the if statement works correctly in release builds too - it just does nothing.
These are just two common cases. There are many more you probably don't know about. So, while expressions with no side effects seem redundant, they're actually functionally important. An optimizer will remove them entirely so there's no performance impact, too.

Strange Pattern: all functions/methods return error-code using the same type in C++

In my last two projects I've seen the strange guideline, "All Methods/Functions should return error-code using some common ERROR_CODE type". In both projects ERROR_CODE is an int typedef.
Is there any good reason doing it in C++? Some MISRA requirement or something like that?
I can see only disadvantages:
If a function should return a value, it is done by argument reference. e.g.:
string s;
ERROR_CODE err = getString(s);
The importance of a function is not obvious. All looks the same. The list of errors conntains hundreds of errors from low level errors to some domain specific errors.
Have you experienced this programming style? Are there good arguments against it or for it?
I think it's a very bad style for several reasons.
Like you've said, it forces you to pass pointers/references to store the actual result of a function.
Like you've said, the unified error code is ugly because it's trying to unify all sorts of errors from all sorts of domains.
It creates an artificial dependency of all the program's modules on the error code system, making it awkward to reuse a single module or small subset of modules in other programs.
Further, since some of the error codes are domain-specific, it's actually introducing dependencies between unrelated object types/modules, since they're all dependent upon a component that's dependent upon the union of all of their possible error types.
My view is that any function/method which has more than a small manageable number of ways it can fail is either overly complex or poorly factored, probably both.
If you really want to return error codes, I would swap things around and pass the pointer to the error code as an argument to the function, and make the actual result the return value. Then I would choose one of these two approaches for implementing the error codes:
The simple way: throw away all abstraction of the error code and simply use int with a few universal error classes.
The heavy object oriented way: Provide a pointer to an internal "error object" where the base class is very abstract and can be shared between all components without introducing any dependency, and where each component defines its own component-specific error objects if needed.
A better approach if you're using C++ would probably be using exceptions...
I've seen it.
kernel programming is that way, except when only one error is possible.
It doesn't sound like a great idea, but neither all that bad of one.
It's not unusual for teams to agree on a common means of returning errors, since this helps in creating a common 'look and feel' to the project's code, just like any other team-wide coding convention. This could help new team members to understand the overall picture quicker, and make maintenance within the team of other peoples' code a little more intuitive.
It's surprising to me that a C++ project is unifying behind errors rather than exceptions, however. There's a discussion of the pros and cons of using exceptions vs error codes here.
I guess one argument in favour of error code handling is if you are using a C-style API that leads you into this approach (cough... Win32... cough).
This idiom is quite common, especially in the C world.
Even though I don't use it myself and I think it makes more harm than good (more on that in the other answers), I do find an advantage of it: a consistent way to report unexpected errors to the call site. Something like the errno variable, but easier to use.
For instance, consider a set of functions:
int a();
std::string b();
double c();
std::list<long> d();
Each of the above functions would indicate the failure in a different way: a() could return an -1, b() an empty string, c() a 0.0 and d() an empty list. That's inconsistent and not quite intuitive. Now imagine a function, whose range covers the entire possible range of the type it returns. That's even worse.
Some APIs also do:
int x(bool* ok);
But that also pollutes each function with an additional argument.
In C, there aren't many possibilities to do in a nice way, unfortunately, if you really need to design such an API that would indicate the different types of failure. In the C++ world, however, you can just use exceptions.
I've seen the argument that when linking to a C++ library compiled by another compiler than is used to compile your binaries, exceptions might not work. While this non-working may totally be true, in actuality, even the linking process need not work (although everyone may be sticking to the standards), so, theoretically, this argument is void. In practice however, it may be (I don't have experience here, sorry), that name mangling conflicts rarely arise, alignment conflicts rarely arise, and, well, all other implementation specific stuff is widely agreed upon, except for exceptions.
Second argument I've seen is run-time performance. While stack unwinding in case of an exception is expensive, I've not yet seen a fair benchmark that compared exceptions to a realistic amount of return code checking.
In my typical C++ I use a mix. I use the slower exceptions for stuff that I really don't expect to happen frequently or code paths that are measured to be rarely executed, but return codes for stuff that is more likely to break and probably called frequently.
Throwing exceptions in a tight loop because some funny condition holds true in every iteration is not cheap (assuming the loop body handles it).

Moving from C++ to C

After a few years coding in C++, I was recently offered a job coding in C, in the embedded field.
Putting aside the question of whether it's right or wrong to dismiss C++ in the embedded field, there are some features/idioms in C++ I would miss a lot. Just to name a few:
Generic, type-safe data structures (using templates).
RAII. Especially in functions with multiple return points, e.g. not having to remember to release the mutex on each return point.
Destructors in general. I.e. you write a d'tor once for MyClass, then if a MyClass instance is a member of MyOtherClass, MyOtherClass doesn't have to explicitly deinitialize the MyClass instance - its d'tor is called automatically.
Namespaces.
What are your experiences moving from C++ to C?
What C substitutes did you find for your favorite C++ features/idioms? Did you discover any C features you wish C++ had?
Working on an embedded project, I tried working in all C once, and just couldn't stand it. It was just so verbose that it made it hard to read anything. Also, I liked the optimized-for-embedded containers I had written, which had to turn into much less safe and harder to fix #define blocks.
Code that in C++ looked like:
if(uart[0]->Send(pktQueue.Top(), sizeof(Packet)))
pktQueue.Dequeue(1);
turns into:
if(UART_uchar_SendBlock(uart[0], Queue_Packet_Top(pktQueue), sizeof(Packet)))
Queue_Packet_Dequeue(pktQueue, 1);
which many people will probably say is fine but gets ridiculous if you have to do more than a couple "method" calls in a line. Two lines of C++ would turn into five of C (due to 80-char line length limits). Both would generate the same code, so it's not like the target processor cared!
One time (back in 1995), I tried writing a lot of C for a multiprocessor data-processing program. The kind where each processor has its own memory and program. The vendor-supplied compiler was a C compiler (some kind of HighC derivative), their libraries were closed source so I couldn't use GCC to build, and their APIs were designed with the mindset that your programs would primarily be the initialize/process/terminate variety, so inter-processor communication was rudimentary at best.
I got about a month in before I gave up, found a copy of cfront, and hacked it into the makefiles so I could use C++. Cfront didn't even support templates, but the C++ code was much, much clearer.
Generic, type-safe data structures (using templates).
The closest thing C has to templates is to declare a header file with a lot of code that looks like:
TYPE * Queue_##TYPE##_Top(Queue_##TYPE##* const this)
{ /* ... */ }
then pull it in with something like:
#define TYPE Packet
#include "Queue.h"
#undef TYPE
Note that this won't work for compound types (e.g. no queues of unsigned char) unless you make a typedef first.
Oh, and remember, if this code isn't actually used anywhere, then you don't even know if it's syntactically correct.
EDIT: One more thing: you'll need to manually manage instantiation of code. If your "template" code isn't all inline functions, then you'll have to put in some control to make sure that things get instantiated only once so your linker doesn't spit out a pile of "multiple instances of Foo" errors.
To do this, you'll have to put the non-inlined stuff in an "implementation" section in your header file:
#ifdef implementation_##TYPE
/* Non-inlines, "static members", global definitions, etc. go here. */
#endif
And then, in one place in all your code per template variant, you have to:
#define TYPE Packet
#define implementation_Packet
#include "Queue.h"
#undef TYPE
Also, this implementation section needs to be outside the standard #ifndef/#define/#endif litany, because you may include the template header file in another header file, but need to instantiate afterward in a .c file.
Yep, it gets ugly fast. Which is why most C programmers don't even try.
RAII.
Especially in functions with multiple return points, e.g. not having to remember to release the mutex on each return point.
Well, forget your pretty code and get used to all your return points (except the end of the function) being gotos:
TYPE * Queue_##TYPE##_Top(Queue_##TYPE##* const this)
{
TYPE * result;
Mutex_Lock(this->lock);
if(this->head == this->tail)
{
result = 0;
goto Queue_##TYPE##_Top_exit:;
}
/* Figure out `result` for real, then fall through to... */
Queue_##TYPE##_Top_exit:
Mutex_Lock(this->lock);
return result;
}
Destructors in general.
I.e. you write a d'tor once for MyClass, then if a MyClass instance is a member of MyOtherClass, MyOtherClass doesn't have to explicitly deinitialize the MyClass instance - its d'tor is called automatically.
Object construction has to be explicitly handled the same way.
Namespaces.
That's actually a simple one to fix: just tack a prefix onto every symbol. This is the primary cause of the source bloat that I talked about earlier (since classes are implicit namespaces). The C folks have been living this, well, forever, and probably won't see what the big deal is.
YMMV
I moved from C++ to C for a different reason (some sort of allergic reaction ;) and there are only a few thing that I miss and some things that I gained. If you stick to C99, if you may, there are constructs that let you program quite nicely and safely, in particular
designated initializers (eventually
combined with macros) make
initialization of simple classes as
painless as constructors
compound literals for temporary variables
for-scope variable may help you to do scope bound resource management, in particular to ensure to unlock of mutexes or free of arrays, even under preliminary function returns
__VA_ARGS__ macros can be used to have default arguments to functions and to do code unrolling
inline functions and macros that combine well to replace (sort of) overloaded functions
The difference between C and C++ is the predictability of the code's behavior.
It is a easier to predict with great accuracy what your code will do in C, in C++ it might become a bit more difficult to come up with an exact prediction.
The predictability in C gives you better control of what your code is doing, but that also means you have to do more stuff.
In C++ you can write less code to get the same thing done, but (at leas for me) I have trouble occasionally knowing how the object code is laid out in memory and it's expected behavior.
Nothing like the STL exists for C.
There are libs available which provide similar functionality, but it isn't builtin anymore.
Think that would be one of my biggest problems... Knowing with which tool I could solve the problem, but not having the tools available in the language I have to use.
In my line of work - which is embedded, by the way - I am constantly switching back & forth between C and C++.
When I'm in C, I miss from C++:
templates (including but not limited to STL containers). I use them for things like special counters, buffer pools, etc. (built up my own library of class templates & function templates that I use in different embedded projects)
very powerful standard library
destructors, which of course make RAII possible (mutexes, interrupt disable, tracing, etc.)
access specifiers, to better enforce who can use (not see) what
I use inheritance on larger projects, and C++'s built-in support for it is much cleaner & nicer than the C "hack" of embedding the base class as the first member (not to mention automatic invocation of constructors, init. lists, etc.) but the items listed above are the ones I miss the most.
Also, probably only about a third of the embedded C++ projects I work on use exceptions, so I've become accustomed to living without them, so I don't miss them too much when I move back to C.
On the flip side, when I move back to a C project with a significant number of developers, there are whole classes of C++ problems that I'm used to explaining to people which go away. Mostly problems due to the complexity of C++, and people who think they know what's going on, but they're really at the "C with classes" part of the C++ confidence curve.
Given the choice, I'd prefer using C++ on a project, but only if the team is pretty solid on the language. Also of course assuming it's not an 8K μC project where I'm effectively writing "C" anyway.
Couple of observations
Unless you plan to use your c++ compiler to build your C (which is possible if you stick to a well define subset of C++) you will soon discover things that your compiler allows in C that would be a compile error in C++.
No more cryptic template errors (yay!)
No (language supported) object oriented programming
Pretty much the same reasons I have for using C++ or a mix of C/C++ rather than pure C. I can live without namespaces but I use them all the time if the code standard allows it. The reasons is that you can write much more compact code in C++. This is very usefull for me, I write servers in C++ which tend to crash now and then. At that point it helps a lot if the code you are looking at is short and consist. For example consider the following code:
uint32_t
ScoreList::FindHighScore(
uint32_t p_PlayerId)
{
MutexLock lock(m_Lock);
uint32_t highScore = 0;
for(int i = 0; i < m_Players.Size(); i++)
{
Player& player = m_Players[i];
if(player.m_Score > highScore)
highScore = player.m_Score;
}
return highScore;
}
In C that looks like:
uint32_t
ScoreList_getHighScore(
ScoreList* p_ScoreList)
{
uint32_t highScore = 0;
Mutex_Lock(p_ScoreList->m_Lock);
for(int i = 0; i < Array_GetSize(p_ScoreList->m_Players); i++)
{
Player* player = p_ScoreList->m_Players[i];
if(player->m_Score > highScore)
highScore = player->m_Score;
}
Mutex_UnLock(p_ScoreList->m_Lock);
return highScore;
}
Not a world of difference. One more line of code, but that tends to add up. Nomally you try your best to keep it clean and lean but sometimes you have to do something more complex. And in those situations you value your line count. One more line is one more thing to look at when you try to figure out why your broadcast network suddenly stops delivering messages.
Anyway I find that C++ allows me to do more complex things in a safe fashion.
yes! i have experienced both of these languages and what i found is C++ is more friendly language. It facilitates with more features. It is better to say that C++ is superset of C language as it provide additional features like polymorphism, interitance, operator and function overloading, user defined data types which is not really supported in C. The thousand lines of code is reduce to few lines with the help of object oriented programming that's the main reason of moving from C to C++.
I think the main problem why c++ is harder to be accepted in embedded environment is because of the lack of engineers that understand how to use c++ properly.
Yes, the same reasoning can be applied to C as well, but luckily there aren't that many pitfalls in C that can shoot yourself in the foot. C++ on the other hand, you need to know when not to use certain features in c++.
All in all, I like c++. I use that on the O/S services layer, driver, management code, etc.
But if your team doesn't have enough experience with it, it's gonna be a tough challenge.
I had experience with both. When the rest of the team wasn't ready for it, it was a total disaster. On the other hand, it was good experience.
Certainly, the desire to escape complex/messy syntax is understandable. Sometimes C can appear to be the solution. However, C++ is where the industry support is, including tooling and libraries, so that is hard to work around.
C++ has so many features today including lambdas.
A good approach is to leverage C++ itself to make your code simpler. Objects are good for isolating things under the hood so that at a higher level, the code is simpler. The core guidelines recommend concrete (simple) objects, so that approach can help.
The level of complexity is under the engineer's control. If multiple inheritance (MI) is useful in a scenario and one prefers that option, then one may use MI.
Alternatively, one can define interfaces, inherit from the interface(s), and contain implementing objects (composition/aggregation) and expose the objects through the interface using inline wrappers. The inline wrappers compile down to nothing, i.e., compile down to simple use of the internal (contained) object, yet the container object appears to have that functionality as if multiple inheritance was used.
C++ also has namespaces, so one should leverage namespaces even if coding in a C-like style.
One can use the language itself to create simpler patterns and the STL is full of examples: array, vector, map, queue, string, unique_ptr,... And one can control (to a reasonable extent) how complex their code is.
So, going back to C is not the way, nor is it necessary. One may use C++ in a C-like way, or use C++ multiple inheritance, or use any option in-between.