I am learning some polymorphism.

The wiki page for rust addresses trait is a method to achieve ad hoc polymorphism, and the page for ad hoc polymorphism says function overloading is an example of ad hoc polymorphism.

Based on my current level of understanding a function is ad hoc polymorphic if providing different types of parameters will invoke different implementations. But trait and function overloading seem so different: trait add constraints on type parameters, any type implementes the trait is acceptable, while function overloading overload on the concrete type, any types that are not overloaded are not acceptable.

Can I say trait and function overloading achieve ad hoc polymorphism in the opposite direction? As trait is by specialization and overloading is by generalization?

PS: In c++, template specialization can also provide different implementations based on type parameter passed in, is that also an example of ad hoc polymorphism?

1

There are 1 answers

1
Jeff Garrett On BEST ANSWER

Implementing a trait involves providing an implementation of a behavior, which is type-specific and separate from other implementations ("ad hoc"), and which may be invoked with the same spelling at the call-site as other implementations ("polymorphic"). It's in the same direction as function overloading.

In C++, you might provide overloads to achieve ad hoc polymorphism:

void foo(const X&) { ... }
void foo(const Y&) { ... }
// can call foo(z) where z is an X or a Y

And you can do the same with traits in Rust:

trait Foo { fn foo(); }
impl Foo for X { ... }
impl Foo for Y { ... }
// can call z.foo() where z is an X or a Y

The "other direction" I think you're referring to is being able to constrain generics by what behaviors the types support. In Rust, this looks like:

fn bar<T: Foo>(t: T) { ... }
// bar can use t.foo()

C++ has an analogy:

template<typename T> concept Foo = requires(T t) { foo(t); };
void bar(Foo auto& t) { ... }
// bar can use foo(t)
// (this uses really new C++, it's written differently in older C++)

Constrained generic functions are not ad hoc polymorphism because they have one implementation which applies to all argument types that implement whatever requirements are placed on them.

In summary, traits provide both ad hoc polymorphism and constraints for generic functions, and some languages like C++ use different devices to achieve the same ends. Ad hoc polymorphism in C++ is typically achieved with function overloading. Template specialization can also achieve it.