Hacker News new | ask | show | jobs
by hellofunk 2118 days ago
You’re talking about really two different issues here. I don’t think anyone would suggest templates can’t get complicated. But they are certainly the doorway into maximum performance over C.
1 comments

No I don't think I'm talking about something else. And I wouldn't submit to the opinion that performance cricitical code needs to be written in C++.

For example, Games are heavy in C++ where there are a lot of abstractions. Engine code is mostly C style as far as I can tell. Optimized code is code that exploits specific properties of systems, hence it is significantly less abstracted than higher-level code.

The stereotypical std::sort example doesn't count, really. There are many reasons why std::sort vs qsort (which are both generic sorting implementations - i.e. not optimized ones) is not significant in practice, but it's still among the most frequently cited examples - hinting that there might be few real wins (with regards to performance) from all this compile time and templates stuff.

Hm, I’m not sure where to start with your assessment here. Your comments on sorting don’t really seem relevant, I don’t think you’re referring to the same kind of compile time programming we’ve been discussing. There’s a difference between generic code, and code that runs at compile time, even though both might actually use the C++ feature of templates. C++ templates are way to write code that supports generics, but they are also a way to do a style of programming referred to as “meta-programming“, these are really not the same thing at all.

While you can certainly do without generics in the language, as proven by the success of many many languages, perhaps at the inconvenience of some developers, compile time meta programming is an entirely different area that only few languages really support. The high frequency trading firms and the game studios I have partnered with are typically using C++ specifically for those compile time programming features. They make dramatic performance differences in a wide range of highly specialized algorithms.

It wasn't me who said "templates" first. (I don't think of them as a practical way to do compile time computation).

I was mostly looking at constexpr and whatever similar things have appeared in C++ lately. And I wanted to know about actual applications of them in the wild that make a difference.

Because, yeah I can precompute a 100K hash table or whatever at compile time, but I can also just do it at program startup (would anyone notice?) which is by far the simplest thing to do. Or I could just generate the data in a separate build step which is probably more hassle compared to constexpr but also probably friendlier in terms of build times in practice.

In embedded systems, often times not all memory is equal. Pre-computing a lookup table at runtime may not be practical due to the limited amount of RAM vs. flash memory. A constexpr or template meta program is, as you touched on, a nice way to do calculations at compile time in the existing language without having to add an explicit autocoding build step. An explicit build step eventually makes sense for sufficiently complex algorithms, but it can be a lot of build system maintenance overhead for small to medium complexity stuff. Implementing esoteric code using obscure syntax may be bad for readability, but keeping it "in the language" has a benefit of limiting the amount of project specific knowledge required to understand it.
Now this I call a reasonable comment! I learned something, thank you.
Thanks! Thinking a bit more about it, I could imagine some performance impacts even on full featured CPUs. With virtual memory and the OS paging stuff in and out of physical RAM under memory pressure, read only data can be swapped out faster than writable data. The former, being immutable, can just be forgotten and then reloaded from disk when it's accessed again, while the latter has to be written to a swap file first, and writes are typically orders of magnitude slower than reads. Doesn't matter as long as you have plenty of RAM though.
Matrix compile time templates like Eigen result in vastly faster code than doing it in C, since many operations can be compile time simplified. C has no way do do this at compile time.

This is just the tip of the iceberg on using templates and classes to make faster, cleaner code.

In C, you could provide a bunch of functions that chain together the permutations of operations that can be optimized. I.e. TransverseMultiplyMatrixInverseDotProduct() or whatever actually makes sense. Since you can't overload operators, folk would have to read through the available functions to find what they need anyway. It wouldn't be pretty, but it would be functional and probably compile down to similar machine code.
No, you cannot, not without putting an incredible amount of work on the programmers plate.

Consider the simple problem of multiplying together a sequence of N matrices of possibly different sizes with the least amount of work. The order you multiply in is determined via some optimization technique. You can try to have a different C function for each N, but eventually you will have some N for which your lib doesn't have the call. Or maybe you'll try to pack pointers into an array and pass that, which is now slower and more memory costly. In any case the order must be solved at runtime.

Templates allow, at compile time for known size matrices, the order to be determined. This cannot be done in generality with C since you cannot in C do it.

And, if the matrices were constexpr, this can be computed at compile time.

So the template method, giving you Turing complete operations, can do things that you cannot do in C.

This is just a simple example, the tip of the iceberg.

Of course you could also just write assembly if you wanted the exact most optimized machine code.

It’s also hard to generalize these things in the form of those kinds of macros. Whereas with something like Eigen, just write your code like normal, you don’t have to worry about the special cases, and the compiler rewrites it for you. That’s one of the nice benefits, one of many, of metaprogramming.

Indeed Eigen is a popular library for its expression templates that make many math operations much faster.
> It wasn't me who said "templates" first.

But you were talking about generics, which implied you were incorrectly conflating that with template meta-programming, since generics are done with templates.

> I don't think of them as a practical way to do compile time computation

Templates are however the most flexible, advance technique for C++ compile-time programming, though the C++ standard is evolving to bring more and more of those features into the language without using templates, i.e. "constexpr if".

My recommendation would be to avoid speculating on what the benefits are of a language or its features if you clearly don't have serious experience using them. It's fine if C++ is not for you.

> But you were talking about generics, which implied you were incorrectly conflating that with template meta-programming, since generics are done with templates.

I'm aware this is a pointless discussion, but please double check your claims are right if we are in "check mode". I did not say "generics".

>> Any examples of using compile time features that make a difference, instead of making code harder to maintian and increasing compile times significantly?

> My recommendation would be to avoid speculating on what the benefits are of a language or its features if you clearly don't have serious experience using them. It's fine if C++ is not for you.

Maybe you shouldn't make such statements if you don't know about my experience. I am speaking from experience, and exchanging subjective experiences isn't worthwhile most of the time, but sometimes (if people don't go down to personal attacks) there is a new viewpoint to find.

> I did not say "generics".

FYI if you’re talking about compile-time programming and you use the word “generic“ (as you did, in the context of a generic sort, which actually does have a meaning related to generics, as the routine works on containers of any type), note that this is a well-established term, which could be confusing if you actually are referring to something else.