In C++, the signature of a function template doesn't necessarily tell you what types you can successfully call it with, nor what the return type is.
Much analysis is delayed until all templates are instantiated, with famously terrible consequences for error messages, compile times, and tools like IDEs and linters.
By contrast, rust's monomorphization achieves many of the same goals, but is less of a headache to use because once the signature is satisfied, codegen isn't allowed to fail.
You can Zeno's-paradox-away the distinction between a bathtub and a kitchen sink, but that doesn't make them the same thing.
This sort of argument change how people understand words, and it also doesn't change how lawyers interpret laws nearly as often as people think. It's still fun, though!
To each his own, but epsilon-delta is my go-to example of formalizing an intuitive concept ("gets closer and closer"), which is a high-level mathematical skill.
The intuition and the formalism are presented together (at least, they should be!). To learn the role of epsilon and delta, the student needs to jump back and forth, finding the correspondences between equations and the motivation. This is a skill that needs practice; this was one of the first places I found the equations dense enough that I couldn't just "swallow them whole".
(The earlier I remember is the quadratic formula, which I first painfully memorized as technical trivia. It took me a couple of years to grasp that it was completing-the-square in general form. Switching between the general and the specific is another skill that you develop)
Yes (at least approximately, I'm fuzzy on the details).
These days it supports both. (IIRC the default is legacy/nonstandard, you select the standard behavior with /fpermission-, and VS adds /fpermission- to newly generated projects)
Yeah, that trade-off makes a lot of sense. It's the logical conclusion of the "templates are textual" model. But C++ loves to have its cake and eat it regardless of the complexity, so it's non-conforming.
(I expect it's possible to construct cases where this difference is observable)
I think checking templates in isolation has value. We use statically typed languages in part to make more error classes locally-verifiable. But bolting that into a mostly-textual system is a mess.
(Checking templates in isolation is particularly valuable in IDEs, which tend to share logic with compiler frontends. IDEs only need that much power to do a passable job because the language is so complex, so I don't know which way this argument points)
`getFoo()` is missing an argument, but you still want to complete Foo's members. If you type `getFoo().getBar()` you want go-to-definition to work on `getBar`.
In clang, we use heuristics to preserve the type in high-confidence cases. (here overload resolution for `getFoo` failed, but there was only one candidate function). This means you can get cascading errors in those cases (but often that's a good thing, especially in an IDE - tradeoffs).
> Surrounding expressions that consume that type will see the error type and suppress any other type errors they might otherwise produce.
We added a slightly-cursed version of this to clang. The goal was: include more broken code in the AST instead of dropping it on the floor, without adding noisy error cascades.
The problem is, adding a special case to all "surrounding expressions that consume that type" is literally thousands of places. It's often unclear exactly what to do, because "consume" means so many things in C++ (think overload resolution and argument-dependent lookup) and because certain type errors are used in metaprogramming (thanks, SFINAE). So this would cost a lot of complexity, and it's too late to redesign clang around it.
But C++ already has a mechanism to suppress typechecking! Inside a template, most analysis of code that depends on a template parameter is deferred until instantiation. The implementation of this is hugely complicated and expensive to maintain, but that cost is sunk. So we piggy-backed on this mechanism: clang's error type is `<dependent type>`. The type of this expression depends on how the programmer fixes their error :-)
And that's the story of how C gained dependent types (https://godbolt.org/z/szGdeGhrr), because why should C++ have all the fun?
(This leaves out a bunch of nuance, of course the truth is always more complicated)
Much analysis is delayed until all templates are instantiated, with famously terrible consequences for error messages, compile times, and tools like IDEs and linters.
By contrast, rust's monomorphization achieves many of the same goals, but is less of a headache to use because once the signature is satisfied, codegen isn't allowed to fail.