7 ms·
Templates are not proper generics. Templates can be used to emulate generics, but they are not the same thing at all. Templates are not first-class citizen of t
by pkolaczk 11y ago
Templates are not proper generics. Templates can be used to emulate generics, but they are not the same thing at all. Templates are not first-class citizen of the type system (they don't survive to the typechecking phase), while generics are. You cannot write a generic list implementation in C++ and have it typechecked.
- fauigerzigerk 11y agoI'd like to hear more about that because I'm not sure I understand. Can you give an example for something you cannot do in C++ in a type safe way that you can do in C#, Java or Swift?
- pkolaczk 11y agoI already gave one. You can't write a generic list implementation and make the compiler prove your code is sound (according to the rules of the C++ type system) for any valid type argument value.
- pjmlp 11y agoYou obviously need to learn about template metaprogramming, enable_if, type traits and SFINAE. C++ templates are Turing complete, you can validate whatever you feel like at compile time.
- pkolaczk 11y agoI'm absolutely aware of enable_if, type traits and SFINAE. But they do not address the concern I raised here. The things you mention come to play on template instantiation, after the concrete (non-generic) types are already known. The problem I mention is that with templates you cannot type check generic code. I can put whatever nonsense enable_ifs on my template declaration and the compiler does not check if they are satisfied by the implementation. You can write the following C++ code and C++ allows it: <template typename T> void foo(const T& arg) { arg.bar(); } This is perfectly fine for a macro system. But this is not how truly generic type system would work. If templates were proper generics, the typechecker would immediately refuse this to compile saying something like: "Error: I can't prove T has the bar() member." > C++ templates are Turing complete, you can validate whatever you feel like at compile time. So please write a template metaprogram that validates if a given C++ class (input to the program, given as a template argument) matches a table schema in the database system (the table name and connection string are also given as template arguments). For fetching the schema, you have to connect to the DB, of course at compile time. If the schema does not match, the compilation should fail ;)
- pjmlp 11y agoBecause whoever wrote foo () was too lazy to make use of type traits and validate that T has a method called bar with zero arguments. Do you want an example how to write it properly? With or without the upcoming concepts TS already in GCC 6.0? Also this example would require T to be an interface with a bar method in C#. Do you also want to the the variant with MI and pure abstract classes in C+?
- pkolaczk 11y ago> Because whoever wrote foo () was too lazy to make use of type traits and validate that T has a method called bar with zero arguments. In a proper generic type system, the compiler validates it, not the programmer. Even if you constrain the type using type traits, the compiler would not check if the implementation satisfies the constraints. I can put a type trait for existence of bar() and then another programmer may rename bar() to baz() forgetting to update the constraint and the code will still compile fine.
- pjmlp 11y agoExcept that reasoning fails with concepts, already available in GCC 6.0 and as a TS.
- pkolaczk 11y agoSo you're saying concepts will reject libraries that compile fine today?
- pjmlp 11y agoThey might, if used properly. I do admit that I need to update myself with what GCC 6.0 allows vs the letter of the TS.
- fauigerzigerk 11y agoI don't think concepts are even necessary to do what pkolaczk wants to do, which is (I think) to constrain the argument to a particular interface, say Bar: template <typename T> void foo(const T& arg) { const Bar* b = arg; b->bar(); } or template <typename T> void foo(const T& arg) { static_assert(is_base_of<Bar, T>::value, "T must be a Bar"); arg.bar(); } I can't say I'm a huge fan of either syntax, but the compiler will perform static type checking as if you had written where T : Bar in C#.
- pjmlp 11y agoNow I am curious about an example where generics are able to do what templates, which are Turing complete, aren't.
- chadzawistowski 11y agoI think of templates as an automated copy+paste mechanism. C++ templates can bloat the compiled executable pretty significantly... If you define a generic Foo<String> and Foo<Widget>, C++ templates will generate two separate binary implementations. C# will use the same implementation, and perform type checks using reflection at runtime. Further support for the idea that C++ templates are an automated copy+paste mechanism is that you're allowed to give templates arguments that are not types. Further reading: https://msdn.microsoft.com/en-us/library/c6cyy67b.aspx https://msdn.microsoft.com/en-us/library/c6cyy67b.aspx
- pjmlp 11y agoIt is not how you think of them, rather what is possible to do with their expressiveness. C# type checks imply a performance hit and are an implementation detail. Nothing prevents a C# compiler to choose another one. It has nothing to do with generics vs templates. For example Modula-3 and Ada compilers use the same approach as C++ for code generation of their generics. So where is that example of something that can only be written with C# generics, but not with C++ templates? A github gist maybe?
- pkolaczk 11y agoIt is not the case of what can only be written, but what can be written and typechecked. C# generics offer much stronger type safety for library writers than C++ templates. C++ templates are not type-checked. C# (and Java, and Scala and Haskell) generics are.
- pjmlp 11y agoYes they are type checked. That is what enable_if, type traits, if constexpr and eventually concepts allow for.