Please stay with me for a short intro. I have been recently trying to connect two pieces of software. One produces messages with certain attributes, the other contains different functions to consume them. Which function to call depends on the message. But not all functions in the second one necessarily take the full message as argument. Some functions take only some particular attribute or a few of them. Additionally, users might want to write their own. And I did not like the solutions I came up with.
Instead of showing the full code, I have written 4 small programs to exemplify. If you take a look at: Rust Playground you will see a Dispatcher
with a HashMap
that links a keyword to a Fn
. In this toy example, the key word is given in the main and the Fn is much simpler than the real stuff. What follows are 4 functions (sum
, offset
, constant
, fcast
) that might be part of the second library or written by the final user.
In the main, the user registers the functions by wrapping them into a closure. Then there are a few calls exemplifying what the system will do when it receives the messages with the payload (the key, x
, y
).
Simple Dispatcher API to the final user: a single function called
register
Extensible: You can easily register a
Fn
with a different signature by wrapping it.
Wrapping is done only once (at registering)
Wrapping can be annoying when there are more arguments or if a more involved casting is required.
So I decided to tackle the only thumbs down (and I failed). The first idea could be to add specific registration functions as seen here: Rust Playground
But results in a complex API and extending requires adding methods to the Dispatcher impl
Another options was to create a rust Enum to contain all cases as shown here: Rust Playground
The Dispatcher API has now a single function. But creating the Handler object is ugly, extending requires reimplementing the call method of the dispatcher and hacking the Handler Enum. Additionally, I have now to match in every single call.
What I would really like to do is something like this: Rust Playground (but implementing the IntoHandler trait for the different function signatures). It provides a simple Dispatcher API, very easy to use and trivial to extend, even in other libraries. However, according to the answers to my previous question is not possible. But more over, some even commented that "fake overloading is the wrong approach".
So my questions are:
- One practical: What would be "the right approach" for this problem?
- One conceptual: When is using traits like
Into<String>
(which also fakes overloading) ok?
If you are still there after all this long text, thanks!