On use, the function will be instantiated:
int length(ListNode__int__ * list) { if (list == NULL) { return 0; } else { return 1 + length(list->tail()); } }
Here, I am using length "as it was intended". However, since the substitution is textual, you can also do strange things. Let's say we add the following code:
int length(double x) { // Overload length() return int(x - 10); } class A { // Define strange type public: double tail() { return 10.0; } }; A my_a; // USE: What happens? int result = length<A>(&my_a); cout << result << endl;
Q: Why do weird things happen?
A: Because, although the result type of A::tail()
is radically different from the result type for
ListNode<T>::tail()
, C++ still allows the
template instantiation length<A>. By contrast, the ML
length function:
fun length(nil) = 0 | length(_::xs) = 1 + length(xs);
cannot accept any argument that is not a "real" list type. You cannot substitute some other function that "looks" like a list type simply by virtue of having some functions defined over it. This issue exists even when we don't take advantage of C++ function and operator overloading, although the existence of overloading does make the problem worse.
On the other hand, you can obviously write things using templates that you can't write in ML.
Thought question: Can you think of a sensible use of C++ templates that would be outlawed by ML's type system? You're actually not qualified to answer this until you've seen higher-order functions and functors; but keep this in mind as the course goes on. If you want my opinion, I have never experienced a case where I thought C++ templates would save me from ML's "restrictive" type system.