What if anything have we learned from C++? [video]
youtube.com
youtube.com
But I am happy I stuck with it as it opened up opportunities to work in a lot of different and interesting domains like games, mobile apps, interactive art installations, trading systems and video and film processing apps. Also, most of my code is platform independent and very efficient.
There are a few interesting alternatives at the moment, namely Rust and Swift, but for now C++ does everything I want and since C++11 it really feels like a much more modern language.
I would prefer it if we had several strong, open langauges that are complements to eachother and which would own the market so developers could focus on solving problems, not learning syntaxes and APIs. Instead we have C# and Java, Python and Ruby, etc.
I'd rather see greater interoperability to enable parts of a project to be written in different languages. The C# ecosystem (F# etc) is closest to this, although see also Scala.
A paper from the man himself on getting a type switch in C++ almost as fast as what you get in OCaml. http://www.stroustrup.com/OOPSLA-typeswitch-draft.pdf
Lot's of other places where he's omitting things because he wants to plug C++.
Also, he also seems to be confused between "an efficient language" and "a language that allows you to create something that runs efficiently".
"Our library-only implementation (...) For many uses, it equals or outperforms equivalent code in languages with built-in type-switching constructs, such as OCaml and Haskell"
In my opinion major weakness of C++ is just that the linker features more or less remained out of the language design. Turbo Pascal already shown eons ago the advantages of having modules instead of obj files. The slowness of compilation is still the major problem of C++ compared to the languages like Turbo Pascal and more recently Go.
Something like TypeScript is to JavaScript, or like Kotlin is to Java. Would make the experience much nicer without having to wait on the slow C++ standardization process or deal with all the backwards compatibility baggage from the past (to a degree).
In terms of playing nice Rust is doing great (no GC, and can create static libraries linkable by C/C++ compilers), but unfortunately requires going through plain C interface.
On the other hand using C libraries is super easy from any language and something compiled 10 years ago still works today.
C++98 code out of GCC has been ABI stable for over 10 years now btw, and we also have some pretty great tools for detecting ABI breakage now, like abi-compliance-checker[1]
[0] https://techbase.kde.org/Policies/Binary_Compatibility_Issue... [1] http://ispras.linuxbase.org/index.php/ABI_compliance_checker
I was specifically picking on Visual Studio and vendors who decided to distribute C++ dlls. Sometimes they provide several versions depending on which Visual Studio version you have installed at the moment.
Well, and you can append new elements to a struct and are guaranteed that the initial sequence of common elements is identical. This is not mentioned explicitly in the C language standard, but it follows as a corollary from point 6.5.2.2.5 of the language standard:
> One special guarantee is made in order to simplify the use of unions: if a union containsseveral structures that share a common initial sequence (see below), and if the unionobject currently contains one of these structures, it is permitted to inspect the commoninitial part of any of them anywhere that a declaration of the complete type of the union isvisible. Two structures share acommon initial sequenceif corresponding members havecompatible types (and, for bit-fields, the same widths) for a sequence of one or moreinitial members.
Consider
a.h
struct a { char aye; short bee; int cee; long dee; };
a.c #include "a.h"
int aye(struct a a) { return a.aye; }
b.h struct b { char aye; short bee; int cee; long dee; double eee; };
b.c #include "b.h"
int bee(struct b b) { return b.bee; }
Now if we add c.h #include "a.h"
#include "b.h"
union ab {
struct a a;
struct b b;
};
The language standard warrants, that the common initial sequence of both structures can be used interchangeably in that union. Since however compilation units a.c and b.c are processed individually without knowledge of union ab this enforces the compiler to use the same memory layout for an initial sequence of member elements for either struct. Hence it is legal to extend structs without out altering the memory layout of the previous elements.The linker coudln't care less about this part of the ABI (calling conventions). For example passing a function pointer to a different library (callback) the linker is completely oblivious to. Heck, the functions which pointers are being being passed around could have been compiled at runtime (JIT).
Calling convention ABIs are a compiler thing, as it's the compiler that emits the machine code that's responsible for setting up the frame in which a function executes. And calling conventions is, where C and C++ differ. On the language level there are not calling conventions (how could there be, as those strongly depend on the machine architecture). However for the various operating systems out there you can find detailed calling conventions for C, but seldomly for C++. And these platform specific C calling conventions usually tightly control both how function (stack) frames are created, which registers may be clobbered, but they also control the memory layout that a C compiler for that platform shall apply on structs. For example the SysV AMD64 ABI strictly nails down the specifics of aggregate type memory layout and function parameter passing. All compilers following that spec will produce code that's compatible with each other, even across library boundaries.
foo (a, b, c)
char *a;
int b, c;
{
/* do something cool here */
}
And there were no "function declarations" (who needs argument type and cardinality checking anyway), no "slash slash" single line comments, no need to declare a return type as int was implied, say goodbye to const and volatile qualifiers, any char array is mutable (including those defined in double quotes), plus be sure to use function pointers thusly: (*some_pointer) (insert, args, here);
Instead of: some_pointer (looks, like, a, function);
Oh yeah, and say adios to struct initialization using the C89 syntax. And it's a no-no to try and initialize a local array along the lines of: char *strings = {
"this", "is", "convenient", "isn't", "it?"
};
So if you wish to assert (pun intended) "that plain-old C really is better", then be sure to acknowledge where a non-trivial amount of what is known as "plain-old C" stems from.The "object-orientedness" of C++ really boils down to implicitly passing the this pointer to member functions, inheritance + virtual functions, and namespaces. All of these can be emulated in what I would call "C with discipline". Just be consistent in your naming conventions, always use a common prefix for globally visible functions and types, and use structs of function pointers whenever you really need virtual functions.
And, before you mention it, use clang to avoid getting the page long templates related errors.
Type-generic data containers can still be implemented with void pointers and very little runtime overhead, for example: http://lxr.nginx.org/source/src/core/ngx_array.h
I am working in DSP project which was started with typical C++ OO BS, finally with ended up with C compiled as C++ + some simple templates for cases as above.
#define MAX(a,b) ({ \
typeof (a) _a = (a); \
typeof (b) _b = (b); \
_a > _b ? _a : _b; \
})
The inability to write template functions can be compensated by designing your function so that it takes a function pointer where the type-specific action occurs. auto max = [](auto a, auto b) {
return (a > b) ? a : b;
};
max (3.1415, 42); // returns double
max (42ul, 78u); // returns unsigned long
max (17, 16); // returns intHow is it template 'nonsense', when those templates do exactly that?
int maxi(int, int);
double: maxd(double, double);
...
#define max(x) _Generic((x), int: maxi, double: maxd, ...default: maxi)C is so tedious to write that even if I didn't have access to C++ I would try something else first when the need to write cross-platform/performant code would come.
The point is: it's not appropriate to evangelise C (or any other language) without pointing out some of its major disadvantages. This is simply spreading misinformation.
This becomes much simpler once you learn how to write your own variadic functions (it's not that hard, though I do admit it could be prettier). Then you just write one single logerrf function or whatever, which 9 times out of 10 you can carry with minor modifications to your next project. Java does try/catch better in the sense that with checked exceptions you can force library users to at least acknowledge exceptions. Without checked exceptions, try/catch just hides the extra int *err argument under the rug, actually increasing the risk of library users not acknowledging edge cases.
>and resource management
I don't like C++ malloc'ing things behind my back. I see it as trading maintainability for instant gratification. The problem is compounded by the way C++ doesn't play nice with gdb/valgrind. Memory leaks and other memory errors are much easier to fix in C than C++.
>C is so tedious
It really isn't, though, if you use it right. Whatever syntactic tedium it has is more than compensated for by the lightning-fast compile time and the infinitely simpler compiler errors (due to no overloading, no templates...)
I agree and I want to add that for a language "with a bias towards system programming" C++ makes strange assumptions about the memory. It assumes that there is only one kind of memory available for every operation (and it does its thing with that by default). Then it goes and further assumes that there is only one way (no finer further details whatsoever) of getting that one and only type memory. It's exactly the one boot fits all kind of thinking that Mr. Stroustrup suggests that C++ hasn't.
But I stuck with it and have found that learning C++ has meant that I think in C++, and transfer this to other languages when I have to write them.
Additionally, the second thing I found was that all other languages I have come across (Obj-C, Java, Swift, JavaScript, PHP, C#) all have enough commonalities in syntax and thought processes that working in them is easy. In some cases, you get to consider them "dumbed-down" C++, and it makes working in them easier (and means approaches to things are different).
So it isn't a bad language after all. Particularly with the changes in C++11, it feels like an entirely new language.
Though I was keen on getting into coding, I was like many other students put off by this approach and only went back to programming many years later with visual basic.
I appreciate that one gets a better understanding of computer science by going really low level (assembler, etc) but I question whether this is the right approach if one wants coding to be more mainstream.
I think coding should be taught in high school like latin or physics, not because kids will all become programmers, or historians or scientists, but because having a basic understanding and culture will help in everyone's life and it gives kids a taste for what a career in that field may look like. And I don't think C++ is the right tool for that.
I think you severely underestimate kids.
There did seem to be too much apologizing for how other people messed up the original idea of C++. Same for patronizing much of the industry. I can't claim it was unwarranted, but a lot of patronizing.