Actions API for xmpp Agent
Follow-up to this merge request
Some people in the chat were wondering why do this. In the current state of the MR, i don't see a clear benefit, except to list all available methods in an enum which is more convenient for "discovery" from a consumer PoV. However, it does not address the concern of optional arguments.
The argument for an Action enum containing action builders would be to allow type-safe command building with optional parameters. Let's take an example: Agent::join_room takes 5 arguments:
- the room to join
- an optional nick (where None means no specific nick)
- an optional password (where None means no specific password)
- a lang string for the status message
- a status message
In this case, only the room to join should be mandatory to give. Some options are lesser used (like status message), and the lang for the status message is hard to handle on a high level of abstraction: most clients don't have UI to specify the language a message is written in, and even if they did most users don't care to click for this. That may be useful for translations of posts in PubSub, but should not be mandatory... just like HTML pages on the web can technically have different language variants in the same document but nobody does that because the UX is not convenient.
On the other hand, some more optional arguments are useful to pass. For example, History settings are clearly useful: when i built a bot with the xmpp crate, it automatically downloaded history downloaded history and the bot started replying to historical messages, and i found no way to disable this on a high-level. I believe the default should be to disable MUC history by default (and use MAM instead), but that will be discussion for another issue. It's still useful to allow it to be specified... and we cannot add infinite arguments to the join_room
method.
What's i'd like to propose instead is a builder pattern for Action, which can be approached in several ways:
client.join_room(&barejid).without_history().send().await
client.action(Action::JoinRoom(&barejid)).without_history().send().await
client.action(Action::join_room(&barejid).without_history()).await
Action::join_room(&barejid).without_history().send(&mut Agent).await
client.action(Action::join_room(&barejid).without_history()).await
I have a preference for option 1 or 3, but i currently have an experimental branch for option 5. I'd like to have feedback on the library consumer UX before i submit a merge request
Note that this approach for consuming the library is not incompatible with the current approach with methods exposing all mandatory and optional arguments. They are complementary ways. However, it has some advantages:
- brevity: optional arguments are just not declared by the consumer
- longer-term API stability: adding optional arguments on an action builder does not break the API, while adding an optional argument on a method does