How can I approximate method overloading? - overloading

I am modeling an API where method overloading would be a good fit. My naïve attempt failed:
// fn attempt_1(_x: i32) {}
// fn attempt_1(_x: f32) {}
// Error: duplicate definition of value `attempt_1`
I then added an enum and worked through to:
enum IntOrFloat {
Int(i32),
Float(f32),
}
fn attempt_2(_x: IntOrFloat) {}
fn main() {
let i: i32 = 1;
let f: f32 = 3.0;
// Can't pass the value directly
// attempt_2(i);
// attempt_2(f);
// Error: mismatched types: expected enum `IntOrFloat`
attempt_2(IntOrFloat::Int(i));
attempt_2(IntOrFloat::Float(f));
// Ugly that the caller has to explicitly wrap the parameter
}
Doing some quick searches, I've found some references that talk about overloading, and all of them seem to end in "we aren't going to allow this, but give traits a try". So I tried:
enum IntOrFloat {
Int(i32),
Float(f32),
}
trait IntOrFloatTrait {
fn to_int_or_float(&self) -> IntOrFloat;
}
impl IntOrFloatTrait for i32 {
fn to_int_or_float(&self) -> IntOrFloat {
IntOrFloat::Int(*self)
}
}
impl IntOrFloatTrait for f32 {
fn to_int_or_float(&self) -> IntOrFloat {
IntOrFloat::Float(*self)
}
}
fn attempt_3(_x: &dyn IntOrFloatTrait) {}
fn main() {
let i: i32 = 1;
let f: f32 = 3.0;
attempt_3(&i);
attempt_3(&f);
// Better, but the caller still has to explicitly take the reference
}
Is this the closest I can get to method overloading? Is there a cleaner way?

Yes, there is, and you almost got it already. Traits are the way to go, but you don't need trait objects, use generics:
#[derive(Debug)]
enum IntOrFloat {
Int(i32),
Float(f32),
}
trait IntOrFloatTrait {
fn to_int_or_float(&self) -> IntOrFloat;
}
impl IntOrFloatTrait for i32 {
fn to_int_or_float(&self) -> IntOrFloat {
IntOrFloat::Int(*self)
}
}
impl IntOrFloatTrait for f32 {
fn to_int_or_float(&self) -> IntOrFloat {
IntOrFloat::Float(*self)
}
}
fn attempt_4<T: IntOrFloatTrait>(x: T) {
let v = x.to_int_or_float();
println!("{:?}", v);
}
fn main() {
let i: i32 = 1;
let f: f32 = 3.0;
attempt_4(i);
attempt_4(f);
}
See it working here.

Here's another way that drops the enum. It's an iteration on Vladimir's answer.
trait Tr {
fn go(&self) -> ();
}
impl Tr for i32 {
fn go(&self) {
println!("i32")
}
}
impl Tr for f32 {
fn go(&self) {
println!("f32")
}
}
fn attempt_1<T: Tr>(t: T) {
t.go()
}
fn main() {
attempt_1(1 as i32);
attempt_1(1 as f32);
}

Function Overloading is Possible!!! (well, sorta...)
This Rust Playground example has more a more detailed example, and shows usage of a struct variant, which may be better for documentation on the parameters.
For more serious flexible overloading where you want to have sets of any number of parameters of any sort of type, you can take advantage of the From<T> trait for conversion of a tuple to enum variants, and have a generic function that converts tuples passed into it to the enum type.
So code like this is possible:
fn main() {
let f = Foo { };
f.do_something(3.14); // One f32.
f.do_something((1, 2)); // Two i32's...
f.do_something(("Yay!", 42, 3.14)); // A str, i32, and f64 !!
}
First, define the different sets of parameter combinations as an enum:
// The variants should consist of unambiguous sets of types.
enum FooParam {
Bar(i32, i32),
Baz(f32),
Qux(&'static str, i32, f64),
}
Now, the conversion code; a macro can be written to do the tedious From<T> implementations, but here's what it could produce:
impl From<(i32, i32)> for FooParam {
fn from(p: (i32, i32)) -> Self {
FooParam::Bar(p.0, p.1)
}
}
impl From<f32> for FooParam {
fn from(p: f32) -> Self {
FooParam::Baz(p)
}
}
impl From<(&'static str, i32, f64)> for FooParam {
fn from(p: (&'static str, i32, f64)) -> Self {
FooParam::Qux(p.0, p.1, p.2)
}
}
And then finally, implement the struct with generic method:
struct Foo {}
impl Foo {
fn do_something<T: Into<FooParam>>(&self, t: T) {
use FooParam::*;
let fp = t.into();
match fp {
Bar(a, b) => print!("Bar: {:?}, {:?}\n", a, b),
Baz(a) => print!("Baz: {:?}\n", a),
Qux(a, b, c) => {
print!("Qux: {:?}, {:?}, {:?}\n", a, b, c)
}
}
}
}
Note: The trait bound on T needs to be specified.
Also, the variants need to be composed of combinations of types that the compiler wouldn't find ambiguous - which is an expectation for overloaded methods in other languages as well (Java/C++).
This approach has possibilities... it would be awesome if there's a decorator available - or one were written that did the From<T> implementations automatically when applied to an enum. Something like this:
// THIS DOESN'T EXIST - so don't expect the following to work.
// This is just an example of a macro that could be written to
// help in using the above approach to function overloading.
#[derive(ParameterOverloads)]
enum FooParam {
Bar(i32, i32),
Baz(f32),
Qux(&'static str, i32, f64),
}
// If this were written, it could eliminate the tedious
// implementations of From<...>.

The Builder
Another approach that addresses the case where you have multiple optional parameters to an action or configuration is the builder pattern. The examples below deviate somewhat from the recommendations in the link. Typically, there's a separate builder class/struct which finalizes the configuration and returns the configured object when a final method is invoked.
One of the most relevant situations this can apply to is where you want a constructor that takes a variable number of optional arguments - since Rust doesn't have built-in overloading, we can't have multiple versions of ___::new(). But we can get a similar effect using a chain of methods that return self. Playground link.
fn main() {
// Create.
let mut bb = BattleBot::new("Berzerker".into());
// Configure.
bb.flame_thrower(true)
.locomotion(TractorTreads)
.power_source(Uranium);
println!("{:#?}", bb);
}
Each of the configuration methods has a signature similar to:
fn power_source(&mut self, ps: PowerSource) -> &mut Self {
self.power_source = ps;
self
}
These methods could also be written to consume self and return non-reference copies or clones of self.
This approach can also be applied to actions. For instance, we could have a Command object that can be tuned with chained methods, which then performs the command when .exec() is invoked.
Applying this same idea to an "overloaded" method that we want to take a variable number of parameters, we modify our expectations a bit and have the method take an object that can be configured with the builder pattern.
let mut params = DrawParams::new();
graphics.draw_obj(params.model_path("./planes/X15.m3d")
.skin("./skins/x15.sk")
.location(23.64, 77.43, 88.89)
.rotate_x(25.03)
.effect(MotionBlur));
Alternatively, we could decide on having a GraphicsObject struct that has several config tuning methods, then performs the drawing when .draw() is invoked.

Related

Make functions instantiate its generic parameter

What would be an equivalent to the following C++ program in rust?
#include <iostream>
#include <vector>
template <typename T>
T stuff() {
return T();
}
int main() {
std::vector<int> vec = stuff<std::vector<int>>();
vec.push_back(1);
for (auto &&i : vec) {
std::cout << i << std::endl;
}
}
I tried the following:
trait Newable{
fn new() -> Self;
}
fn stuff<T: Newable>() -> T {
T::new()
}
I tried using a newtype for this -
struct NwVec<T>{
vec: Vec<T>
}
impl<T> Newable<T> for NwVec<T>{
fn new() -> Self {
NwVec { vec: Vec::new() }
}
}
and used it like so:
fn main() {
let x: NwVec<i32> = stuff::<NwVec<i32>>();
}
but I get a
error[E0277]: the trait bound `NwVec<i32>: Newable<NwVec<i32>>` is not satisfied
--> src\main.rs:2:25
|
2 | let x: NwVec<i32> = stuff();
| ^^^^^ the trait `Newable<NwVec<i32>>` is not implemented for `NwVec<i32>`
|
= help: the following implementations were found:
<NwVec<T> as Newable<T>>
note: required by a bound in `stuff`
Is there a way to achieve what the C++ program achieves?
P.S.: I am rather new to rust, I am really sorry if the solution to this is trivial.
Maybe there was a mixup when you entered the code that you say gave you the error you provided, because that same code did not yield that specific error when I tried it.
Either way, you were close. Consider this code:
trait Newable {
fn new() -> Self;
}
fn stuff<T: Newable>() -> T {
T::new()
}
#[derive(Debug)]
struct NwVec<T> {
vec: Vec<T>
}
impl<T> Newable for NwVec<T> {
fn new() -> Self {
NwVec { vec: Vec::new() }
}
}
fn main() {
let x: NwVec<i32> = stuff::<NwVec<i32>>();
println!("{x:?}");
}
Playground
All I changed was:
Added #[derive(Debug)] to NwVec<T> so we could print it out
I removed the type parameter <T> on Newable<T> from your original impl<T> Newable<T> for NwVec<T>. This is because the Newable trait itself, as provided in your post, is not generic, so it takes no type parameter.
I imagine this is something of a learning exercise, but in case you were curious, you may be interested in std::default::Default which is a trait somewhat similar to your Newable in that implementations provide a simple and consistent way to create a "default" version of something. Vec itself is an implementer, so you can call e.g. Default::default() or Vec::default() wherever a Vec<T> is expected. Check this playground.
Adding to the excellent answer by #JorgeIsraelPeña, in case you insist on Newable, you don't need a newtype. You can implement a trait for a type as long as either the trait or the type are yours (well, the actual rules are a bit more complicated). That means you can implement Newable directly for Vec:
impl<T> Newable for Vec<T> {
fn new() -> Self {
Vec::new()
}
}
fn main() {
let x = stuff::<Vec<i32>>();
println!("{x:?}");
}
Playground.

How do I clone a Rc trait object and cast it to another trait object?

This is a follow up question from Rust dynamic cast trait object between different taits. The solution provided there works really well when we use references for trait objects, but this time I am trying to do the same with Rc pointers. For example
I have a super trait named TraitAB and 2 traits named TraitA and TraitB
So when I first create a trait object of type TraitAB instead of using a Box, now I use an Rc pointer.
I need a variable of type TraitA to be a reference of ab
Here I made a very minimal example:
use std::rc::Rc;
trait TraitAB: TraitA + TraitB {
fn as_a(&self) -> Rc<dyn TraitA>;
fn as_b(&self) -> Rc<dyn TraitB>;
}
trait TraitA {}
trait TraitB {}
struct MyType {}
impl TraitAB for MyType {
fn as_a(&self) -> Rc<dyn TraitA> {
Rc::clone(self)
}
fn as_b(&self) -> Rc<dyn TraitB> {
Rc::clone(self)
}
}
impl TraitA for MyType {}
impl TraitB for MyType {}
fn main() {
let a: Rc<dyn TraitA>;
let b: Rc<dyn TraitB>;
{
let mut ab: Rc<dyn TraitAB> = Rc::new(MyType {});
a = ab.as_a();
b = ab.as_b();
}
}
This doesn't work though. According to the error messages:
error[E0308]: mismatched types
--> src/main.rs:15:19
|
15 | Rc::clone(self)
| ^^^^ expected struct `std::rc::Rc`, found struct `MyType`
|
= note: expected reference `&std::rc::Rc<dyn TraitA>`
found reference `&MyType`
error[E0308]: mismatched types
--> src/main.rs:18:19
|
18 | Rc::clone(self)
| ^^^^ expected struct `std::rc::Rc`, found struct `MyType`
|
= note: expected reference `&std::rc::Rc<dyn TraitB>`
found reference `&MyType`
as_a and as_b can't know self is actually an Rc pointer.
Is there a way to do the cast of a cloned shared pointer?
methods as_a and as_b can't know self is actually an Rc pointer.
Actually, that's not true! There's a rarely used feature that allows self to be taken as various standard kinds of references (Rc<Self>, Box<Self>, etc.).
That means that you can rewrite your TraitAB as
trait TraitAB : TraitA + TraitB {
fn as_a(self: Rc<Self>) -> Rc<dyn TraitA>;
fn as_b(self: Rc<Self>) -> Rc<dyn TraitB>;
}
Unfortunately, as written, as_a and as_b move self: Rc<Self>, since Rc<T> doesn't implement Copy (only Clone). One way to fix this is to simply clone ab before passing it into these methods. This also means that you don't need to clone the self inside the method. (playground link)
let ab: Rc<dyn TraitAB> = Rc::new(MyType{});
let _a: Rc<dyn TraitA> = ab.clone().as_a();
let _b: Rc<dyn TraitB> = ab.clone().as_b();
Using the nightly-only feature arbitrary_self_types, it's possible to make as_a and as_b take self as &Rc<Self> (which looks weird to me since it's a reference to a reference). This allows ab.as_a() to be called without moving ab. The only problem with this approach is that TraitAB is no longer object-safe1, so Rc<dyn TraitAB> no longer works. (playground link).
According to the tracking issue for arbitrary self types, the object safety question is still open. I'm not really sure what the rules are right now.
You need to implement TraitAB on RC<MyType>:
use std::rc::Rc;
trait TraitAB {
fn as_a(&self) -> Rc<dyn TraitA>;
fn as_b(&self) -> Rc<dyn TraitB>;
}
trait TraitA {}
trait TraitB {}
struct MyType {}
impl TraitAB for Rc<MyType> {
fn as_a(&self) -> Rc<dyn TraitA> {
Rc::clone(self) as Rc<dyn TraitA>
}
fn as_b(&self) -> Rc<dyn TraitB> {
Rc::clone(self) as Rc<dyn TraitB>
}
}
impl TraitA for MyType {}
impl TraitB for MyType {}
fn main() {
let a: Rc<dyn TraitA>;
let b: Rc<dyn TraitB>;
{
let mut ab: &TraitAB = &Rc::new(MyType {});
a = ab.as_a();
b = ab.as_b();
}
}
By the way, I don't see any reason for TraitAB to extend TraitA + TraitB, but you can extend and implement TraitA and TraitB for Rc<MyType> as well.
This is a working example with the implemented functions for TraitA and TraitB.

How do I create an array of function pointers of different prototypes?

I have a few functions defined like this:
ParentClass* fun1();
ParentClass* fun2();
ParentClass* fun3(bool inp=false);
ChildClass* fun4();
ChildClass* fun5(int a=1, int b=3);
I would like to put them into an array of some kind as follows:
void* (*arr[5])() = {
(void* (*)())fun1,
(void* (*)())fun2,
(void* (*)())fun3,
(void* (*)())fun4,
(void* (*)())fun5
}
Now I would like to use this array of functions simply as
for(int i=0; i<5; i++)
someFunction(arr[i]());
Now I realize here that the issue is void* (*arr[5])(), but given that I only want to use the functions without supplying an argument, I would like all of these to be part of the same array.
These are very C-style ways to do it, though. Is there a better way to do it using Templates in C++?
C-style or not, what you have is straight undefined behaviour. Use lambdas:
void (*arr[5])() = {
[] { fun1(); },
[] { fun2(); },
[] { fun3(); },
[] { fun4(); },
[] { fun5(); }
};
These are okay because they perform the call through the function's correct type, and are themselves convertible to void (*)().
Forwarding the returned value stays simple enough, since the lambda provides a context for the conversion. In your case, since ChildClass supposedly inherits from ParentClass, an implicit conversion is enough:
ParentClass *(*arr[5])() = {
[]() -> ParentClass * { return fun1(); },
[]() -> ParentClass * { return fun2(); },
[]() -> ParentClass * { return fun3(); },
[]() -> ParentClass * { return fun4(); },
[]() -> ParentClass * { return fun5(); }
};
but given that I only want to use the functions without supplying an argument
It simply doesn't work like that. Did you ever wonder, then when you're putting function declarations in a header, why you have to write default parameters into the header and cannot place it in the definition in the implementation source file?
That's because the default parameters are in fact not "embedded" into the function, but used by the compiler to augment a function call with those parameters at a calling location, where those parameters are omitted. (EDIT: Also, as #Aconcagua so keenly observed in a comment, since default parameters are usually defined as part of a header function declaration, any change of the default values requires a full recompilation of any compilation unit that included those headers, ergo function declarations, for the change to actually take effect!)
While it's perfectly possible to do some really weird type casting madness to construct an array of function pointers like that, eventually you'll have to cast back to the original function call signature in order to not invoke undefined behavior.
If anything you'll have to bind the function pointer, together with a set of default parameters in some type that abstracts away the calling, does supply the parameters, and to the outside offers a polymorphic interface. So you'd have a std::vector<function_binder> or function_binder[] where function binder has an operator() that calls the function.
But when you're doing binding in the first place, you can bind it in an anonymous function, i.e. lambdas. At the time of lambda instantiation the default parameters are bound.
std::vector<void(*)()> fvec = {
[]{ func0(); },
[]{ func1(); },
[]{ func2(); }
};
You can use std::bind
std::function<ParentClass *(void)> arr[5] = {
std::bind(&fun1),
std::bind(&fun2),
std::bind(&fun3, false),
std::bind(&fun4),
std::bind(&fun5, 1, 3)
};
now you can do
for(int i=0; i<5; i++)
arr[i]();
You have to make sure every function parameter of all functions are bound.
This also works well with member functions. You just have to bind the object reference (e.g. this) as first parameter.
A c++20 solution:
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
template<auto f, class R, class...Args>
struct explicit_function_caster {
using Sig=R(Args...);
using pSig=Sig*;
constexpr operator pSig()const {
return [](Args...args)->R {
return static_cast<R>(f(std::forward<Args>(args)...));
};
}
};
template<auto f>
struct overload_storer_t {
template<class R, class...Args>
constexpr (*operator R() const)(Args...) const {
return explicit_function_caster<f, R, Args...>{};
}
template<class...Args>
auto operator()(Args&&...args)
RETURNS( f( std::forward<Args>(args)... ) )
};
template<auto f>
overload_storer_t<f> generate_overloads={};
#define OVERLOADS_OF(...) \
generate_overloads< \
[](auto&&...args) \
RETURNS( __VA_ARGS__( decltype(args)(args)... ) ) \
>
which is a lot of boilerplate, but gets us:
ParentClass* (*arr[5])() = {
OVERLOADS_OF(fun1),
OVERLOADS_OF(fun2),
OVERLOADS_OF(fun3),
OVERLOADS_OF(fun4),
OVERLOADS_OF(fun5)
};
void (*arr2[5])() = {
OVERLOADS_OF(fun1),
OVERLOADS_OF(fun2),
OVERLOADS_OF(fun3),
OVERLOADS_OF(fun4),
OVERLOADS_OF(fun5)
};
basically generate_overloads<x> takes a constexpr callable object x and lets you cast it at compile time to a pointer to a function of any compatible signature and call it with (almost) any signature.
Meanwhile, OVERLOADS_OF converts a function name into a constexpr object that does overload resolution on that function name. I use it here because fun3 as a function pointer does not know about its default arguments, but at overload resolution time it does.
In this particular case, it is far easier to just write toy lambdas to do this work; this is just an attempt to automate writing those toy lambdas for arbitrary compatible signatures.
Since you have tagged question with C++14 you should not use function pointers!
With C++14 you should prefer std::function and lambdas.
Also you should not use C style array, but only std::array and/or std::vector.
Also avoid raw pointers, use std::unique_ptr and std::shared_ptr.
So simplest and best way to solve it is:
std::array<std::function<ParentClass*()>,5> arr {
[]() { return fun1(); },
[]() { return fun2(); },
[]() { return fun3(true); },
[]() { return fun4(); },
[]() { return fun5(7, 9); }
};
Why not simple array of pointers like in #Quentin answer? He used lambdas, but he can't use lambda which binds anything (if you need to).

(Compile-time) unit testing which of several overloads is called

Consider the following piece of code:
struct A {};
struct B : A {};
bool f(A,A) { /* ... */ }
bool f(B,B) { /* ... */ }
Now suppose I have somewhere something like
// ...
b = f(x,y);
// ...
I would like to ensure by a (probably compile-time, or alternatively run-time) unit test that a particular overload of f is called by this sequence of code. Let's say f(B,B) is some specialized, optimized version of f(A,A), so that it is functionally equivalent, yet faster. I cannot determine which function has been called by just looking at the result.
One possibility, of course, is letting f set some global flag.
Another possibility is something like
template <class X, class Res> struct Distinguish {
using Tag = X;
Res m_res;
explicit Distinguish (Res res) : m_res (res) { }
operator Res () const { return m_res; }
};
Distinguish<char[1], bool> f (A, A) { /* ... */ }
Distinguish<char[2], bool> f (B, B) { /* ... */ }
and then examine decltype(f (x,y))::Tag. Yet that is ugly, since I have to change the signatures of f.
Is there any better way?
Step thru it in a debugger. You might have to put a carriage return before the curly brace in your function definitions.

C++: Is it possible to use dynamic binding with a template parameter?

I have a template function which accepts a function-object ('functor') as a template parameter:
template <typename Func> int f (void) {
Func func;
return func ();
};
struct Functor {
virtual int operator () (void) = 0;
};
struct Functor0 : Functor {
int operator () (void) {
return 0;
}
};
struct Functor1 : Functor {
int operator () (void) {
return 1;
}
};
I want to avoid an if-else block like:
int a;
if (someCondition) {
a = f<Functor0> ();
}
else {
a = f<Functor1> ();
}
Is there a way to use something similar to dynamic binding, i.e something like:
a = f<Functor> (); // I know this line won't compile, it is just an example of what I need
and decide in runtime what (derived) type is passed as the template parameter?
Is there a way to use something similar to dynamic binding
No. This is fundamentally impossible. At some point in your code you need to have the case distinction. Of course, that doesn’t have to be written manually; you can use macros (or again templates) to generate the necessary code. But it needs to be there.
One way to avoid the check (if that is REALLY what you want to do), is to use an array - ..
Functor* fp[] = { new Functor0(), new Functor1() };
now - use someCondition as an index.
a = (*fp[someCondition])();
this relies simply on run-time polymorphism rather than the redundant template mechanism you are using... (btw. don't forget to cleanup!)
Of course, this is nasty and frankly redundant, the overhead of the if will be insignificant, but the clarity it adds to the code is significant...