> It might be nice if a type itself could indicate whether it's hashable and, if so, what it's hash function is. Then, if you create a hash table with that key type, it automatically uses the hash function defined by that type.
> Now you need some sort of constraints or type bounds in your generics. That's what traits in Rust and bounds in Java and C# give you.
Isn't having a function "Hash", called in your template, that takes your type as argument (and give compiler error if the function doesn't exist for this type, as a consequence of substituting in your type) sufficient for this?
Yes, C++'s duck typing approach is one solution to this.
It takes the solution out of the type system, which keeps the type system simpler.
But it effectively turns your compiler into an interpreter, and an interpreter which may fail.
One way to think of C++'s notoriously huge, incomprehensible template compile time errors is that they are effectively stack traces of the template expansion interpreter running at compile time. When you see one of those errors, you have to figure out which chain of compile-time execution led to it.
Everything that's frustrating about dynamically typed errors that makes users reach for static types is exactly true of C++'s template system as well. (And, conversely, everything that's powerful and simple about dynamic types is true of C++'s template system.)
It's actually even worse in C++ because of SFINAE. The "interpreter" running at compile time in C++ doesn't just abort on the first error. It's like an interpreter for a dynamically typed language that also supports overloading. Any time a function has an error, the interpreter backtracks and tries the next overload. If all overloads fail, then it keeps unwinding.
So what you get isn't just a call stack on a template expansion error, it's a call tree of every place it tried to get to that failed.
> Now you need some sort of constraints or type bounds in your generics. That's what traits in Rust and bounds in Java and C# give you.
Isn't having a function "Hash", called in your template, that takes your type as argument (and give compiler error if the function doesn't exist for this type, as a consequence of substituting in your type) sufficient for this?
In other words, duck typing