How C++ Resolves a Function Call
preshing.com
preshing.com
There's no notion of a "primary" template. Templates are looked up like functions are.
C++ has rather complex function overloading rules that differ substantially from template overloading rules. The former is a hierarchical list of rules, the latter is based on partial ordering. D uses partial ordering for both.
D doesn't need argument dependent lookup, because it has modules.
D lookup sees all the declarations in a module at once, not just ones prior to the point of use.
The end result works pretty much the same, and hardly anyone notices the difference. Except for that last point - in C and C++, the order of declarations is inverted. The private functions come first, the public ones last, because lookup is dependent on the lexical order. D code is written with the public ones first, private ones last.
Despite the power of D's overload mechanism, my advice is to use overloading modestly, not cleverly. You've written your best code when a newbie looks at it and remarks "pshaw, I could have written this! Why does Walter make so much money?"
This is a replacement for calling the superclass, but it uses C3 method resolution order.
It's been a while that I've hacked CL, but I remember method combinators being used in mixin-style programming[1]. A call-next-method is a simplification tool in that context, and it doesn't hard-couple your generic functions. With concepts now in C++, I wouldn't be surprised to see a resurgence of template-mixins, and there it really helps to have some introspection into the partial ordering.
[1] That is, Flavors mixins, not dlang mixins ;)
Sometimes I think about the advice on how to carve a figure in stone - chip away anything that is not part of the figure.
The same applies to programming. Easy to say, hard to do.
D works for basically the same set of problems as C++, in much the same way. D, not bound by history ("mistakes", you could say) could be simpler than C++, and able to do some things more neatly, but not enough so to match C++'s momentum—also a product of history. Since D came out, C++ has evolved in ways hard to keep up with. Some make it more like D, but those don't help D.
Rust is different enough from C++ to have some hope of carving out its own space, while trying to address the same sort of problems C++ does. Rust also abandons history, with consequences like D. However, Rust is developing its own complexities. In the end, if it survives, Rust and Rust code will be fully as complex as C++ and C++ code, just off in a slightly different direction.
But it is too early to know whether Rust too will, in the end, fail to find a mainstream place. Ada and Pascal both once had far wider use than Rust, and faded. Ultimately, C++ can do anything Rust can, has capabilities Rust is not expected ever to match, and is still evolving fast. So, for anything that might need to be maintained by somebody else someday, it is easier to believe that a C++ programmer could be found to do it.
In the end, the only true determiner of whether a language succeeds is if a miracle occurs. C got one, C++ got one, Java got one, Javascript got one. Python probably got one. I don't know of any others newer than Fortran. Julia and Rust still have a chance.
But a borrow checker does not change the set of possible programs. It only identifies the subset of possible programs that would need "unsafe" blocks.
In the absence of a borrow checker, libraries are left to carry the responsibility to define an API that is hard to misuse. Such an API could be slower than what one would define for a library to be used under a borrow checker. But code written to satisfy a borrow checker is sometimes slower than code that doesn't need to.
Once you have Turing completeness you have the full set of possible programs, end of story. Languages aren't about changing the set of possible programs, they're about making good ones easier to write, and bad ones harder.
Yet, C++, D, and Rust are much more like one another than any of them is like any other language. Your Turing Completeness tells you less than nothing about any important distinction between them.
C++:
typedef struct S { int x; } S;
D: struct S { int x; }
There are a lot of things like that, and it adds up.struct S { int x; };
is perfectly valid C++
People have learned to deal with the quirky behavior of the tag name space, but it's still quirky and serves no purpose.
I wrote Bjarne back in the 1980s that the tag name space should be removed from `class` as that wasn't necessary for backwards compatibility with C. He replied no as it would have broken compatibility with existing C++ code.
I never, ever, typedef struct tag names. I have only ever seen typedefs like that in C headers. All C++ code I ever see looks like your D example.
I have to wonder if you meant to post something else, or if you have lost touch with what C++ code looks like.
C++:
template<class T> T func(T t) { ... }
D: T func(T)(T t) { ... }
orC++:
void f(long);
void test() {
f(1); // calls f(long)
}
void f(int);
D: void f(long);
void test() {
f(1); // calls f(int)
}
void f(int);
orC++:
int f(int a[3]) { return a[4]; } // undefined behavior
D: int f(int[3] a) { return a[4]; } // index out of bounds error
Of course, you can use `array<int>` in C++, and all the above can be worked around, but it just is more work and doesn't look as good. template <typename T> T func(T t) { return t; }
auto func(auto t) { return t; } // same, "abbreviated"
C++ is often not as nice to type as D, or as Rust. That's backward compatibility for you. But having literally tens of billions of lines of code in production, and millions of programmers who know how to use it, counts for a lot.Miracles are Heaven sent, right? What does Hell send? Maledictions? https://www.powerthesaurus.org/miracle/antonyms
Sun committed a billion dollars to promoting Java—and the opportunity-cost loss is probably a big part of what killed them. It still would not have been enough to secure a place for Java, except that Java offered MS sharecroppers a road to a sort of freedom. Ada got even more $promotion than Java, in its day, but faded.
C got its miracle on the coattails of Unix, C++ on C's. Javascript rode on Netscape. (Who remembers MS Silverlight? MS spent as much as Sun.)
Python, if does survive, got its miracle the hard way. Perl and Ruby once seemed more secure than Python does now. Rust and Julia are going the hard route.
All it takes to fade away is not getting that miracle, mo maledictions needed.
To be successful, it had to correctly deal with every nuance of the printf spec. cppreference got a couple of these incorrect wrt to modifiers. Not something a routine user would notice, but a pedantic one would. (Sorry, I don't remember exactly what the mistakes were.)
I still use cppreference because it is so dang convenient. But I don't rely on it when perfection is required.
It's really too bad that copyright forces everyone writing a manual to rewrite & rephrase things. I wish the C++ Standard was online.
One online reference I dearly like is https://www.felixcloutier.com/x86/index.html which has saved me so much time. But it was created by scanning the actual reference manuals, so barring scanning errors, it is exactly correct. I gave up using reformulations of the CPU instruction set long ago, they had too many mistakes.
Ahem, warlocks. Be careful or I'll turn you into a newt.
Perhaps a better, less gender-ambiguous term would be "sourcerer" indicating someone who deals in the miracles of transforming source code.
[0] https://www.britannica.com/topic/witchcraft/Witchcraft-in-Af...
Note to anyone trying to implement a language - don't bother reading tutorials or textbooks on a language. Just the Standard. Otherwise you'll be sorry.
[1] https://stackoverflow.com/questions/tagged/language-lawyer%2... [2] http://foldoc.org/language%20lawyer
A tutorial it ain't. Neither is it a guide, an overview, a textbook, a nutshell, or a marketing document.
Just the facts, Ma'am.
PlantUML works well for sequence diagrams, but for the rest, the output is not pleasing to look at.
Sorry, but no. Terminators hate us because they were programmed in a mix of COBOL and 6502 assembler [0]
[0] https://www.theterminatorfans.com/the-terminator-vision-hud-...
Concepts were supposed to help, but based on what I've heard, they sometimes make the error messages even worse, so I'm not sure.
The discussion about C++ lookup rules actually really reminded me of Julia, where functions are quite often overloaded and it is not always trivial to figure out which one should be called. For lack of a better source, there is something about that in this talk: https://youtu.be/TPuJsgyu87U?t=989
And your error messages. ;)
Maybe someday we'll have a language that is efficient and also allows creating efficient and usable DSLs. C++ ain't it.
Edit: perhaps D would actually be that language?
C++ constraints change the game here. Esoteric template errors will be a thing of the past
In the example in the article - I would go to some trouble to avoid having both:
namespace galaxy {
void blast(Asteroid* ast, float force);
}
andtemplate <typename T> void blast(T* obj, float force);
either blasting asteroids happens in the context of galaxies, or it doesn't. If there are _different kinds_ of blasting of asteroids - very well, make that explicit.
Also,
bool blast(Target target);
would be somewhat confusing, since people may expect `blast()` to not return anything and will neglect to check the returned value. And wouldn't it make more sense to just have a default amount of force for the blast? ... again, if it's a different kind of blast, don't name both functions the same.
PS:
* "Better is a good name than fine oil" (that's a biblical proverb). * Don't be a smart-ass when naming! You'll smile for a second, others will cry for years. * Don't be stingy with a few more characters in your name - we can handle it.
Oh no! You just got burned (maybe). Make sure you turn on your compiler's warnings to find bogus-but-legal implicit conversions.
I would also be happy to read more articles like this one. I personally don't use C++ other than for small side projects, but it's a world fascinating to explore.
In a way, it does use a compiler to resolve the candidate functions, but it doesn't go through all the compilation stages. And it's not even the same compiler as when you hit compile :)
[0]: https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B
[1]: https://www.edg.com/
- there, I fixed for you. The compiler doesn't chose on its own whim, it's you who made mistakes and a good IDE allows you to correct it.