I don't think you've understood. If it can compile the whole program, that means it must have ran the preproccesor. If it can run the preproccesor on 6MB of C in 1/100th of a second, a faster preproccesor is not going to do much for compile times since it isn't the bottleneck.
SQLite is C, and C header files tend to be trivial in comparison to their template-loaded C++ counterparts. Even though Firefox is only a few orders of magnitude bigger in terms of source code it takes exponentially longer still to compile.
Could you please point to some good m4 learning and reference resources?
The only time I had to write m4 was admittedly in the context of autotools, but I found it really difficult to get answers to my questions about how everything worked.
Could you please point to some good m4 learning and reference resources?
The only time I had to write m4 was admittedly in the context of autotools, but I found it really difficult to get answers to my questions about how everything worked.
looked up these flags, since I didn't know all of them:
-C: compile but do not link (I think this is covered by -E)
-E: stop after running the preprocessor
-H: print the name of each header file included, indenting child #includes (what do you use this for? is it printed to stderr?)
-P: inhibit the generation of line markers from the preprocessor (I've used this before, but can't recall the problem it solves? Not expanding __LINE__?)
-nostdinc: do not search standard system directories for header files (/usr/include, /usr/local/include, ..., this is standard in the Linux kernel, since there is no libc)
-undef: do not predefine any system-specific or GCC macros (probably to not expand occurrences of sequences like "__GNUC__" and others from unexpectedly being expanded).
-x <language>: specify the language, rather then letting the compiler guess based on the file extension (is this required?)
> -P: inhibit the generation of line markers from the preprocessor (I've used this before, but can't recall the problem it solves? Not expanding __LINE__?)
It prevents #line directives which are useful for a C compiler but erroneous for javascript.
Meh, it's just using the C PreProcessor, cpp, but driven through GCC.
The C preprocessor is pretty simple (well, until you start wanting to evaluate C expressions as part of your #ifdefs) and very well-known. It's not inherently tied to C (QED), so it makes sense. There are other cases where people use it on something other than C, but as kevin_thibedeau mentions, he'd be better served with a more powerful (and generic) macro processor such as M4.
As another abuser of the C preprocessor, I'll point out that you can greatly simplify your call to gcc... by not using gcc, just call cpp directly:
cpp -P -H $main $out
should be equivalent, unless I'm missing something. And since somebody was asking why use -H, I'm guessing it's just for the useful verbosity of it. I've found it also causes helpful notices to be printed like "header guards may be useful for the following file..."
Yes, preprocessor is available as a standalone tool for preprocessing source files in assembly language (.S = input file before preprocessing, .s = output file after preprocessing or source file which does not require preprocessing).
Of course standalone preprocessor can be (ab)used to preprocess Javascript source files and any other files, as grandparent commenter suggested.
Lambdas. Concepts. Ten types of casts. Templates of templates. Everything and the kitchen sink is in there.
You need a language lawyer to figure out anything but the most basic interactions. For example,
1. What's the practical difference between an abstract class and an interface?
2. When do you have a copy constructor run instead of a cast on initialization if both are defined?
3. When would you use a non-virtual destructor?
What happens when you hire people? Isn't it better to have a small language that everyone understands in its entirety, and has to go out of their way to surprise you?
I think that now having auto, decltype, and decltype(auto) all in the language is confusing at best. constexpr also has slightly unintuitive semantics. The problem with all of the additions to C++ isn't whether they're useful individually, it's how as a whole the language is basically a gigantic ball of special cases. C++ is extremely powerful, but also nearly impossible to understand fully.
While perfectly fine, this comment unironically reinforces the GP's assertion of "how [C++] as a whole the language is basically a gigantic ball of special cases"
What specifically annoys me about C++ and is demonstrated by this example is that the simplest possible expression of an algorithm is almost certainly not the most efficient or desirable way to do what you are trying to accomplish.
In a language designed for humans, the simplest expression of a loop (e.g. `for (auto paths : m) {}`) would use references not value copying. You'd have to go out of your way to do the it the dumb way, which you would only do when you have a specific reason to do so.
C++, on the other hand, is only really an effective language in the hands of people who have either fully internalized the 1,000 page specification, or wasted a depressing number of synaptic connections on memorizing minute trivia about what constructs to use under what circumstances.
I say this as someone who works with C++ on a daily basis :(
> C++, on the other hand, is only really an effective language in the hands of people who have either fully internalized the 1,000 page specification, or wasted a depressing number of synaptic connections on memorizing minute trivia about what constructs to use under what circumstances.
No. You use profiling tools and optimize hotspots. Pareto principle applies here so you look at 20% of program tops.
Rest is irrelevant and can be executed as inefficiently as you please as long as you got your big O complexity right.
Isn't C++ still pretty much the fastest language out there, except Fortran for some numerical applications? I thought that's the main reason to use it over Python/Java/etc.
Hence why already back in 1993, when faced with the option of Turbo C 2.0 vs Turbo C++ 1.0, I could not understand why bother with C at all, still don't.
Who said anything about Python or Java? In any case Java and C++ are roughly similar. The next tier of languages such as Rust or Haskell are within a small constant factor in the usual benchmarks. But quoting such benchmarks is questionable because the C and C++ implementations require much more man-hours of hyper optimization to get into that top-tier position. The real important takeaway is that the first or second attempt in C++, by someone who is not a language lawyer, is nowhere near the maximum achievable speed. Whereas the first or second attempt by a similar layman in a reasonable language like Haskell is not only faster than the initial C++ version, but has fewer bugs as well.
Speaking as someone who has spent time optimizing programs in both languages, Rust is certainly not in the same tier as Haskell. It should be in the same tier as C or C++. If there's a program where it's not, then we consider it a bug. (And indeed, those exist. :-) But they are fixable!)
C++ and Java are absolutely not similar in terms of performance. Java requires a virtual machine, C++ compiles to binary. Not in the same league.
And in regard to the first draft of a C++ program being slow until you spend lots of time optimizing it, when comparing to say Haskell, that is not at all my experience. I'm generally able to write clean and efficient programs in C++ on the first draft, and they are invariably more performant than if I had written it in a slower language, without a significantly greater amount of effort.
Java doesn't require a VM per se, there are plenty of commercial JDKs that compile straight into native code.
In case you want to state that a VM is like a language runtime in that case, C++ also needs one for handling exceptions, RTTI, global constructors/destructors, floating point emulation,...
I used to despise C++... but now I work on it every day, and while I don't think it's great, it is not so bad. Turns out my hatred was entirely for the std library. At my work, we simply don't use it. And thus `auto` hardly saves anything, so we don't use that either, and I don't miss any of it.
> In a language designed for humans, the simplest expression of a loop (e.g. `for (auto paths : m) {}`) would use references not value copying.
In C++ values are first class, making 'auto x' an implicit reference would be surprising for anybody with experience with the language model. It is also consistent[1] with the template deduction rules. I strongly believe that not not having first class values in a language with mutation is a design mistake [2].
[1] IIRC the ill designed initialization_list has special rules for auto.
[2] C++ references are not first class which is also a mistake.
> In a language designed for humans, the simplest expression of a loop (e.g. `for (auto paths : m) {}`) would use references not value copying. You'd have to go out of your way to do the it the dumb way, which you would only do when you have a specific reason to do so.
But I would expect
auto x = y;
to create a new variable by copying with type-deduction from y, not a reference (or even const reference) to y. If I want a reference anywhere in the language I always have to say so explicitly. As such, I find it perfectly normal that
for(auto x : y)
create a copy of the elements of y while
for(auto& x : y)
creates a reference to the elements of y. Reversing this just within for-loops would only add to the confusion. Defaulting to references over values just for auto where everywhere else values are the default and references need to be specified would also only add to the confusion.
Of course you may now say that one should have done it right from the start, but this is then an argument about the initial decisions in the late 80s, not about the use of auto in C++11.
Regarding the specification, I am incredibly happy that there is a specification I can trust and nowadays a series of different compilers which largely implement this specification instead of some "model-implementation" which implicitly defines the language and may look entirely different next week.
> But I would expect "auto x = y;" to create a new variable by copying
Why would you expect that? There are plenty of examples of other referentially transparent languages where "x = y" means x and y refer to the same thing, not different things (one newly created) initialized to the same value. Maybe you expect it to work the way it does because that more closely resembles how C++ has worked for you in the past, which is a bit of a circular argument.
> Of course you may now say that one should have done it right from the start, but this is then an argument about the initial decisions in the late 80s, not about the use of auto in C++11.
Are you sure you're making a point – because I can't see one. Seems more about unnecessary bitching about C++ being different from [some-different-language].
If they could do anything more stupid as introducing a galling difference and a special case to variable initialisation with auto, it would be to do exactly that, but because “some other languages work more like that”.
error: invalid initialization of non-const reference of type ‘std::_Bit_reference&’ from an rvalue of type ‘std::_Bit_iterator::reference {aka std::_Bit_reference}’
Heh, when I first heard that C++ vectors were bitvectors I was like "that can't be right? You can't get sensible references to members that way!" But it turns out that C++ is fine with breaking parametricity so references to bitvector elements just don't compile.
I wouldn't say C++ is fine with it. vector<bool> is widely viewed as a mistake. I would actually say it's one of the few inconsistencies in a standard library that tends to be very consistent.
The problem is that (quite rightly) the C++ standard committee tries very hard to not break existing code. There isn't really an easy way to deprecate a specialization of this container without causing 32x more memory use if someone was relying on it, and even worse it would be a silent breaking change.
I mean, this isn't the only case of broken parametricity I've come across in C++ codebases. Though it's the only one in the stdlib.
I know vector<bool> is controversial (and I understand it can't be "fixed" now), I was just surprised that something breaking parametricity so blatantly was ever agreed upon in the first place -- in more functional languages parametricity is kinda much more jealously guarded. Bit of a culture shock there, is all :)
I have to comment on this, even though it's almost completely irrelevant to the blog post. I saw "do_sth" so I wanted to check where the writer was from. Germany. Aha. :-)
I love how reliably abbreviating "something" (e.g. "sth", "smth" or "sthg") indicates that the person isn't from an English-speaking country. I wonder why this abbreviation has never caught on in English-speaking countries. I think the abbreviations got popularised in non-English-speaking countries by English dictionaries.
I think the more common idiomatic "abbreviation" would be "do_stuff" when you don't want to type out or say "something".
I'm sure it's not valid across the board, but most of the internet shortenings that we use in english are acronyms---lol, stfu, wtf, rofl, hbu, asl, etc. I'm actually having a hard time thinking of some common abbreviations. I guess "func" short for "function" is a common example.
Plus old programmers had to pay a heavy vowel tax so many, even unnecessary, abbreviations stick with us. I worked with an older guy on a game once, "extern struct CollisionManager g_clisn_mngr" is an example of the sort of things we did...
Because as you point out yourself, there really is no need for that abbreviation. You could say "do_stuff" and it would have approximately the same meaning, but not be an undecipherable, ambiguous abbreviation.
"That must be a bug, or the result of hardware failure, or an erroneous report from the user, or maybe there's some other possibility I haven't thought of."
Similarly OT, a pet peeve of mine is how Germans and others consistently pronounce (the eg. SQL datatype) VARCHAR as var-CHAIR or sometimes var-CZAR (war czar, warczaw) when they pronounce CHAR/CHR correctly.
Out of interest, what do you consider to be the correct pronunciation of CHAR? There seems to be considerable variation in how people pronounce it (see e.g. [1,2]). Personally I have always used the '/tʃɑr/' one, and similar for VARCHAR.
I've never heard it pronounced that way, although 'care' is how the first syllable in the word 'character' is pronounced.
I've always heard it pronounced var char (the parts rhyme). Char is pronounced like when you burn/blacken a steak. "Char-grilled food is cooked over or under direct heat so that its surface becomes slightly black"
If I'm understanding you correctly, then most English speakers would call that correct. It's short for "character" so is pronounced as the first syllable of that (with a hard 'ch') not like the word "char" is pronounced. I think I personally would swap between the two fairly randomly, probably due to learning to code from text-based sources and not hearing it pronounced till much later.
To be clear: I do not mean the /k/ sound, but the /x/ or /χ/ (voiceless velar/uvular fricative), which is seldom used in English, except when properly pronouncing the names of Scottish lochs, or the name of J.S. Bach. Maybe it's not even used at all in English, but only in Scottish, but we're getting off-topic already.
If I were consciously trying to pronounce "char" as an English speaker would, I would probably say /tʃɑr/.
I'm a native anglophone living in the UK. I abbreviate "something" as "sthg" sometimes. I wouldn't do it in a function/variable/method/class/... name, but then I don't think I'd use "something" as part of such a name in the first place in anything I wasn't very confident would only ever be throwaway code.
Given the timestamps of the two English respondents in favour of "sth", I am tempted to amend my hypothesis to say it's a European thing, and more predominant in continental Europe.
Another point to mention (which I think adds to the conclusion) is that by losing compatibility with the C preprocessor you'd lose compatibility with, well, C.
This means breaking of both C++ code that uses C libraries legitimately and "C++" code that's actually C with new/delete (or "the horror" as we put it).
I would also add that when you're doing low-level work that requires mixing a bit of assembly and C (Or C++, but I mainly stick to C), being able to access the preprocessor from assembly is really nice. The alternative is redefining tons of stuff so you can use it in your assembly. It's a niche use-case obviously, but it is still a nice use-case regardless and I'd wager you could do this with lots of other languages if you ever had a want/need.
> by losing compatibility with the C preprocessor you'd lose compatibility with, well, C.
Thankfully C++ no longer needs it to gain market share, it can stand on its own, while cleaning up the warts that caused unsafe code as a means of getting adopted.
"We have converted most of the CRT sources to compile as C++, enabling us to replace many ugly C idioms with simpler and more advanced C++ constructs. The publicly callable functions are still declared as C functions, of course (extern "C" in C++), so they can still be called from C. But internally we now take full advantage of the C++ language and its many useful features."
Note the reference to ugly C idioms.
Also all major C compilers are written in C++, including clang and gcc, did you miss that as well?
CRT is an optional component of Windows software, a layer above ntdll and kernel32. Anyone can easily compile a program without C runtime library using /Zl compiler option. In this case, only Win32 and native API functions will be available, but not functions like printf() or strcmp().
So latest versions of CRT could be rewritten in C++, but this has nothing to do with documented OS API or even low-level undocumented native API, which are both still pure C.
C code is considered legacy by Microsoft with C++ being the official systems programming language, hence why they dropped support for newer C versions, except for what is required by ANSI C++ standard.
I don't think C++ will ever shrink as a language (i.e., drop features), but we can reduce the learning surface for newcomers by making it simpler, more consistent, and relegating C-isms under the "backwards compatibility"umbrella.
Maybe dropping compatibility with C is a good thing?
All other languages wanting to interface with C seem to be using libffi or something. Currently C++ gets a shortcut, but in the future maybe it could go through an FFI.
It'd still be compatible with C from libraries, just not source. Those libraries would have to ship header files free of macros of course.
I don't see how losing backwards compatibility would be a good thing per se. Even if the preprocessor were considered a problem (which is disputed), it could coexist with a new FFI system that could be implemented.
Losing backwards compatibility is usually a price to pay, not an objective. As an example, Python 3k chose to lose partial compatibility to 2.7 in order to change some parts of the language. While the user and maintainer community still debates if the change itself was a good decision (a different discussion IMO...), probably most will agree that the incompatibility bit has been and will be for some time a source of pain.
I think a more accurate version of Betteridge's law says: when a headline asks a question, the answer is always the less surprising answer. It just happens that usually the more attention-grabbing way to write the headline is the one that makes "no" the less surprising answer.
The Betteridge-compliant version of this article would have been titled "Can we do without the C++ preprocessor?".
After reading about all the hoops the author is willing to jump through to avoid using the preprocessor, I was expecting the conclusion to be, yes, it turns out we still need it.
Thankfully no, M0s nearly come in cracker jack boxes now days. A lot of what used to be on 8bits are moving to M0s because why the heck not.
Commercially advertised prices are around 60 cents in bulk, corporate buys in the 100s of thousands are going to be cheaper than that. Death to 8bits! :)
I am missing the motivation to purge the preprocessor - only reason he gives is the paradigm that the preprocessor is considered bad practice. I fail to see why.
The preprocessor is a useful tool that can save you time and make code more readable and portable. Conditions at compile time guarantee that the compiler is not subjected to a specific portion of code, and it offers the only way to define a constant value without having an implicit type for that.
Considering the use of C/C++ outside pure computer programming, like embedded systems or digital signal processing, where portability, code size and target specific substitutions or optimisations matter, there is simply no reason and no way to get rid of the preprocessor without breaking things.
Sure you can use it in obscure and wrong ways, but it is not the job of the language to act as a nanny and prevent you from doing evil by restricting access to dangerous toys.
CPP is not without warts. It complicates static analysis (machine and human), for one thing. You need the definition of variable foo or function bar? Great, which one? Who made the last assignment to foo and what its value could be? Does this ifdefed snippet here count?
It is also not without very legitimate uses. Feel free to not use the preprocessor if you don't want (you're still using it with `#include` though), but it is very useful for specific use cases, and there is no real reason to remove support for it.
Author here, I didn't intend to give a motivation for purging it, many people in the C++ community want to and I wanted to explore the feasibility of that in the current status.
> like embedded systems or digital signal processing, where portability, code size and target specific substitutions or optimisations matter, there is simply no reason and no way to get rid of the preprocessor without breaking things.
It certainly is, I know embedded projects where they use template meta programming to get an even more advanced code generator.
The post seems to be more about evaluating alternatives to preprocessor-based solutions to common problems; even when alternatives exist, reasonable people can disagree about whether they're actually better, but I think most would agree that it would be nice to have a proper module system instead of using textual includes, or that the fact that macros cannot be namespaced and can lead to ODR violations is not awesome.
Anyway, the post ends saying
> With current C++(17), most of the preprocessor use can’t be replaced easily.
The thing is all people don't use C++ the same way - I've often found myself using a small amount of C++ mixed with large amounts of C written by others - my use of C++ needs to live with other's C headers, their #defines and #includes - my use of C++ is no more or less valid than your's
BTW cpp is not slow, not compared with other parts of C++ compilers
That's a myth afaik. Is there any standard way besides macros to really ensure the code will be inlined? In particular, the suggestively named inline keyword just doesn't work like that.
The preprocessor is a workable but somewhat poor tool for inlining code due to several reasons (no overloading, no sensible macro scoping, template argument lists clash with macro argument lists, etc). However, it's quite a reasonable tool for helping to force inline code in a nonstandard but somewhat portable way. See, for example, EIGEN_ALWAYS_INLINE at https://eigen.tuxfamily.org/dox/Macros_8h_source.html
Sticking with stuff that's in the standard, "constexpr" is, among other things, a more strongly-suggested "inline".
Also, inlining is likely if you compile with -02/-03 and declare the function with internal visibility (in an anonymous namespace or with "static", although the latter is deprecated in favor of the former in C++).
OCaml doesn't have a C-style preprocessor, but I sometimes wish it did have one. One case is where a function has changed its type signature, eg. adding a parameter, but you still want to be able to write code that can compile with the old and new versions of the library. It would be quickest to write:
#if HAVE_OLD_LIB
f 1 2;
#else
f 1 2 3;
#endif
The actual solution in pure OCaml is a huge pain. Usually you have to add another module which is conditionally compiled.
Luckily in OCaml you can write ‘ocamlopt -pp cpp’ to use the C preprocessor on selected files.
Yes, but I don't know if you're talking about the C++ (templates and constexpr's & whatnot) or the C preprocessor. Macros? Get rid of those and you kill my logging solution.
I'm wondering if anyone has tried to use another language - I'm thinking Ruby - as a pre-processor for C++ code. I know people have pre-processed C++ code with various tools - for example Qt - but I'm thinking of just replacing # pre-processor statements with something like Rails based templates.
The .cc file was similar, calling Python functions to get the function definitions from separate files: I built one directory for each class, where I would put each big function or several related small functions in its own file, and they would be found and combined automatically.
For each class, there was a vars.cc file which contained member variables, with their declaration line, initialization and destruction in consecutive lines: the declaration went to the .h file, the initialization to the constructor, and the destruction to the destructor. This way I avoided forgetting to release something and had a good overview of all variables and their life cycles.
Here is an example of generating constant names from a Python list:
The same idea was also used in the Bison/Yacc grammar file:
#!%token <markup> T_QMATH_DIRECTIVE
%token <markup> T_DIRECTIVE_DEFINITION
%token <markup> T_DIRECTIVE_CONTEXT
for d in qmath_directives:
#" "%token <markup> T_DIRECTIVE_${d.upper()}
I've used it also for other languages like Java where it cuts down the boilerplate. For instance, the package names are automatically generated from the file path.
I've seen it done (on a large-ish codebase), using Perl as a preprocessor for C. It looked good on paper and we were really enthusiastic when we came up with the idea, but it quickly degenerated into the proverbial ad-hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp.
In retrospect, we could have done worse, like use C++ :-).
A while ago, in a fit of defmacro-envy, I wrote a preprocessor that would let you wrap Python snippets in #python/#endpython blocks: http://codepad.org/5B388Wsh. This lets you write silly things like http://codepad.org/eS443WPA. I bet the same idea isn't too hard to implement in Ruby, but I don't know enough to try it myself.
I never really used it much - generating C code with Python print statements turned out to look uglier than I thought it would, and most of my use cases were better handled with X macros (https://en.wikipedia.org/wiki/X_Macro) or by generating a separate file and #include'ing it. But your description reminded me of it; you might like the idea.
sometimes I'd use C macro just because it's so darn hard to write capturing lambda code in C++. But capture lambda is suppose to be better and safer. I should use it more.
165 comments
[ 4.9 ms ] story [ 43.1 ms ] threadtcc can fully compile all 6MB of sqlite in 1/100th of a second.
You are right.
In the end I opted for a sed/awk/cat combo instead.
The only time I had to write m4 was admittedly in the context of autotools, but I found it really difficult to get answers to my questions about how everything worked.
http://blog.00null.net/post/144763147991/use-the-unix-m4-as-...
The only time I had to write m4 was admittedly in the context of autotools, but I found it really difficult to get answers to my questions about how everything worked.
-C: compile but do not link (I think this is covered by -E)
-E: stop after running the preprocessor
-H: print the name of each header file included, indenting child #includes (what do you use this for? is it printed to stderr?)
-P: inhibit the generation of line markers from the preprocessor (I've used this before, but can't recall the problem it solves? Not expanding __LINE__?)
-nostdinc: do not search standard system directories for header files (/usr/include, /usr/local/include, ..., this is standard in the Linux kernel, since there is no libc)
-undef: do not predefine any system-specific or GCC macros (probably to not expand occurrences of sequences like "__GNUC__" and others from unexpectedly being expanded).
-x <language>: specify the language, rather then letting the compiler guess based on the file extension (is this required?)
It prevents #line directives which are useful for a C compiler but erroneous for javascript.
The C preprocessor is pretty simple (well, until you start wanting to evaluate C expressions as part of your #ifdefs) and very well-known. It's not inherently tied to C (QED), so it makes sense. There are other cases where people use it on something other than C, but as kevin_thibedeau mentions, he'd be better served with a more powerful (and generic) macro processor such as M4.
Of course standalone preprocessor can be (ab)used to preprocess Javascript source files and any other files, as grandparent commenter suggested.
You need a language lawyer to figure out anything but the most basic interactions. For example,
1. What's the practical difference between an abstract class and an interface?
2. When do you have a copy constructor run instead of a cast on initialization if both are defined?
3. When would you use a non-virtual destructor?
What happens when you hire people? Isn't it better to have a small language that everyone understands in its entirety, and has to go out of their way to surprise you?
Interface? You are talking about the C++ language, right?
If Sutter's metaclasses get into C++20 C++ could indeed have an equivalent to interface enforced by the compiler.
C++ doesn't have "interfaces". No wonder you think there's too much stuff.
Use auto&.
In a language designed for humans, the simplest expression of a loop (e.g. `for (auto paths : m) {}`) would use references not value copying. You'd have to go out of your way to do the it the dumb way, which you would only do when you have a specific reason to do so.
C++, on the other hand, is only really an effective language in the hands of people who have either fully internalized the 1,000 page specification, or wasted a depressing number of synaptic connections on memorizing minute trivia about what constructs to use under what circumstances.
I say this as someone who works with C++ on a daily basis :(
No. You use profiling tools and optimize hotspots. Pareto principle applies here so you look at 20% of program tops.
Rest is irrelevant and can be executed as inefficiently as you please as long as you got your big O complexity right.
Pick the right language.
I'll take my RAII and destructors, thank you very much.
And with Python you use heavily optimized native libraries (Numpy & co.) where it matters.
And in regard to the first draft of a C++ program being slow until you spend lots of time optimizing it, when comparing to say Haskell, that is not at all my experience. I'm generally able to write clean and efficient programs in C++ on the first draft, and they are invariably more performant than if I had written it in a slower language, without a significantly greater amount of effort.
In case you want to state that a VM is like a language runtime in that case, C++ also needs one for handling exceptions, RTTI, global constructors/destructors, floating point emulation,...
In C++ values are first class, making 'auto x' an implicit reference would be surprising for anybody with experience with the language model. It is also consistent[1] with the template deduction rules. I strongly believe that not not having first class values in a language with mutation is a design mistake [2].
[1] IIRC the ill designed initialization_list has special rules for auto. [2] C++ references are not first class which is also a mistake.
But I would expect
to create a new variable by copying with type-deduction from y, not a reference (or even const reference) to y. If I want a reference anywhere in the language I always have to say so explicitly. As such, I find it perfectly normal that create a copy of the elements of y while creates a reference to the elements of y. Reversing this just within for-loops would only add to the confusion. Defaulting to references over values just for auto where everywhere else values are the default and references need to be specified would also only add to the confusion.Of course you may now say that one should have done it right from the start, but this is then an argument about the initial decisions in the late 80s, not about the use of auto in C++11.
Regarding the specification, I am incredibly happy that there is a specification I can trust and nowadays a series of different compilers which largely implement this specification instead of some "model-implementation" which implicitly defines the language and may look entirely different next week.
Why would you expect that? There are plenty of examples of other referentially transparent languages where "x = y" means x and y refer to the same thing, not different things (one newly created) initialized to the same value. Maybe you expect it to work the way it does because that more closely resembles how C++ has worked for you in the past, which is a bit of a circular argument.
> Of course you may now say that one should have done it right from the start, but this is then an argument about the initial decisions in the late 80s, not about the use of auto in C++11.
Yes, that's exactly the point I am making.
If they could do anything more stupid as introducing a galling difference and a special case to variable initialisation with auto, it would be to do exactly that, but because “some other languages work more like that”.
error: invalid initialization of non-const reference of type ‘std::_Bit_reference&’ from an rvalue of type ‘std::_Bit_iterator::reference {aka std::_Bit_reference}’
http://stackoverflow.com/questions/30376032/error-invalid-in...
The problem is that (quite rightly) the C++ standard committee tries very hard to not break existing code. There isn't really an easy way to deprecate a specialization of this container without causing 32x more memory use if someone was relying on it, and even worse it would be a silent breaking change.
I know vector<bool> is controversial (and I understand it can't be "fixed" now), I was just surprised that something breaking parametricity so blatantly was ever agreed upon in the first place -- in more functional languages parametricity is kinda much more jealously guarded. Bit of a culture shock there, is all :)
I feel it's largely worked out, and is well understood.
I feel it's largely worked out, and is well understood. I
I love how reliably abbreviating "something" (e.g. "sth", "smth" or "sthg") indicates that the person isn't from an English-speaking country. I wonder why this abbreviation has never caught on in English-speaking countries. I think the abbreviations got popularised in non-English-speaking countries by English dictionaries.
I think the more common idiomatic "abbreviation" would be "do_stuff" when you don't want to type out or say "something".
[1] https://english.stackexchange.com/questions/60154/how-to-pro... [2] http://www.stroustrup.com/bs_faq2.html#char
Disclaimer: not an English native speaker
I've always heard it pronounced var char (the parts rhyme). Char is pronounced like when you burn/blacken a steak. "Char-grilled food is cooked over or under direct heat so that its surface becomes slightly black"
If I were consciously trying to pronounce "char" as an English speaker would, I would probably say /tʃɑr/.
Another point to mention (which I think adds to the conclusion) is that by losing compatibility with the C preprocessor you'd lose compatibility with, well, C.
This means breaking of both C++ code that uses C libraries legitimately and "C++" code that's actually C with new/delete (or "the horror" as we put it).
If you did want to do this, you'd run a C processor on the C code first.
Thankfully C++ no longer needs it to gain market share, it can stand on its own, while cleaning up the warts that caused unsafe code as a means of getting adopted.
https://blogs.msdn.microsoft.com/vcblog/2014/06/10/the-great...
"We have converted most of the CRT sources to compile as C++, enabling us to replace many ugly C idioms with simpler and more advanced C++ constructs. The publicly callable functions are still declared as C functions, of course (extern "C" in C++), so they can still be called from C. But internally we now take full advantage of the C++ language and its many useful features."
Note the reference to ugly C idioms.
Also all major C compilers are written in C++, including clang and gcc, did you miss that as well?
CRT is an optional component of Windows software, a layer above ntdll and kernel32. Anyone can easily compile a program without C runtime library using /Zl compiler option. In this case, only Win32 and native API functions will be available, but not functions like printf() or strcmp().
So latest versions of CRT could be rewritten in C++, but this has nothing to do with documented OS API or even low-level undocumented native API, which are both still pure C.
https://msdn.microsoft.com/en-us/library/jj620896(v=vs.110)....
C code is considered legacy by Microsoft with C++ being the official systems programming language, hence why they dropped support for newer C versions, except for what is required by ANSI C++ standard.
https://herbsutter.com/2012/05/03/reader-qa-what-about-vc-an...
Our focus in Visual C++ is on making a world-class C++ compiler
Our primary goal is to support "most of C99/C11 that is a subset of ISO C++98/C++11."
We do not plan to support ISO C features that are not part of either C90 or ISO C++.
Also the future of Windows lies on UWP, and C is certainly not a way of writing UWP APIs, unless one enjoys low level COM Windows 95 style.
Finally, the remaining C code is slowly being migrated to C++
https://www.reddit.com/r/cpp/comments/4oruo1/windows_10_code...
Meaning of auto, export templates, exception specifications were the biggest ones, there a few minor ones as well.
All other languages wanting to interface with C seem to be using libffi or something. Currently C++ gets a shortcut, but in the future maybe it could go through an FFI.
It'd still be compatible with C from libraries, just not source. Those libraries would have to ship header files free of macros of course.
Losing backwards compatibility is usually a price to pay, not an objective. As an example, Python 3k chose to lose partial compatibility to 2.7 in order to change some parts of the language. While the user and maintainer community still debates if the change itself was a good decision (a different discussion IMO...), probably most will agree that the incompatibility bit has been and will be for some time a source of pain.
The Betteridge-compliant version of this article would have been titled "Can we do without the C++ preprocessor?".
Hmm, okay, and what happens when someone puts that thing in a macro?
Some macros can be horribly ugly, but I'm not sure replacing __FILE__ with compiler-supported magic is an improvement.
D doesn't have a preprocessor, and so that's just what it does:
http://dlang.org/spec/traits.html#specialkeywords
BTW, __FILE__ is compiler supported magic (well, preprocessor, but they are the same thing).
Maybe some of the 8-bit micros still don't..?
Commercially advertised prices are around 60 cents in bulk, corporate buys in the 100s of thousands are going to be cheaper than that. Death to 8bits! :)
> like embedded systems or digital signal processing, where portability, code size and target specific substitutions or optimisations matter, there is simply no reason and no way to get rid of the preprocessor without breaking things.
It certainly is, I know embedded projects where they use template meta programming to get an even more advanced code generator.
Anyway, the post ends saying
> With current C++(17), most of the preprocessor use can’t be replaced easily.
and I think we can all agree on that.
BTW cpp is not slow, not compared with other parts of C++ compilers
That's a myth afaik. Is there any standard way besides macros to really ensure the code will be inlined? In particular, the suggestively named inline keyword just doesn't work like that.
You can work around this using per-compiler macros, which I guess is another reason why CPP is to stay.
Also, inlining is likely if you compile with -02/-03 and declare the function with internal visibility (in an anonymous namespace or with "static", although the latter is deprecated in favor of the former in C++).
Luckily in OCaml you can write ‘ocamlopt -pp cpp’ to use the C preprocessor on selected files.
One of the things it did was to generate the function prototypes so that a typical .h file would look like this:
The .cc file was similar, calling Python functions to get the function definitions from separate files: I built one directory for each class, where I would put each big function or several related small functions in its own file, and they would be found and combined automatically.For each class, there was a vars.cc file which contained member variables, with their declaration line, initialization and destruction in consecutive lines: the declaration went to the .h file, the initialization to the constructor, and the destruction to the destructor. This way I avoided forgetting to release something and had a good overview of all variables and their life cycles.
Here is an example of generating constant names from a Python list:
The same idea was also used in the Bison/Yacc grammar file: I've used it also for other languages like Java where it cuts down the boilerplate. For instance, the package names are automatically generated from the file path.In retrospect, we could have done worse, like use C++ :-).
I never really used it much - generating C code with Python print statements turned out to look uglier than I thought it would, and most of my use cases were better handled with X macros (https://en.wikipedia.org/wiki/X_Macro) or by generating a separate file and #include'ing it. But your description reminded me of it; you might like the idea.