Search code examples
rustoverloadinggeneric-programmingargument-dependent-lookupopen-closed-principle

Rust's alternative for C++ ADL overloaded functions?


There's a library which provides a generic function and some implementations to work with:

#include <iostream>

namespace lib {
  struct Impl1 {};
  struct Impl2 {};

  void process(Impl1) { std::cout << 1; }
  void process(Impl2) { std::cout << 2; }

  template<typename T> void generalize(T t) { process(t); }
}

I want to extend it via external code. Here's how C++ allows to do it:

#include <lib.h> // the previous snippet

namespace client {
  struct Impl3 {};

  void process(Impl3) { std::cout << 3; }
}

int main() { // test
  lib::generalize(client::Impl3{}); // it couts 3
}

Note: lib's code knows nothing about the client's one and performs no dynamic dispatch nonetheless. How can I achieve the same in my Rust code? (If I can't, is anything alike planned?)


Solution

  • Sure, this is exactly what traits are for:

    pub mod lib {
        pub trait Impl {
            fn process(&self);
        }
    
        pub struct Impl1 {}
        pub struct Impl2 {}
    
        impl Impl for Impl1 {
            fn process(&self) {
                println!("1");
            }
        }
    
        impl Impl for Impl2 {
            fn process(&self) {
                println!("2");
            }
        }
    
        pub fn generalize<T: Impl>(t: T) {
            t.process();
        }
    }
    
    mod client {
        pub struct Impl3 {}
    
        impl super::lib::Impl for Impl3 {
            fn process(&self) {
                println!("3");
            }
        }
    }
    
    fn main() {
        lib::generalize(client::Impl3 {});
    }
    

    See it on the Playground.