-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore: rewrite api #192
chore: rewrite api #192
Conversation
27b1509
to
e156e83
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Somewhat of a feat to get that working, I guess :) I consciously stayed away from such a solution because of what I suspected it would get me into.
I'll list some pros and cons from my perspective (comparing to the mechanism I suggested):
Pros of this version:
- in some twisted way more idiomatic Rust than adding extra reply parameters
- more type-safe in edge-cases (the reply parameters left some highly theoretic room for constructing wrongly typed replies)
Cons:
- Can
EntityRef
s be passed around at all any more because of the complex types? This is notably missing in the tests. Can you show a struct or function definition using such a type? - more complicated types, more boilerplate needed (for marginal benefits? i.e. slightly more idiomatic and slightly more type-safe)
- The definition of an entity (command, events, handlers) now becomes distributed over the different command impls. This makes it harder to get a full picture of the functionality of an entity.
- tries to work around deficiencies in Rust's enums by opening up the Cmd type hierarchy and then closing it down again with type-level trickery (as you know I come from the same thinking wrt static typing but becoming more and more fond of simpler pragmatic solutions than perfect ones)
- (this was also the case before but) interface and implementation are tightly coupled. Now it's even harder than before to provide multiple implementations for the same (cmd, reply) interface.
In total, most of these points might be reasonably acceptable. The main blocker for me is whether the EntityRef
type is still usable at all (or how it can be made so).
eventsourced/src/lib.rs
Outdated
E: EventSourced, | ||
{ | ||
cmd_in: mpsc::Sender<(E::Cmd, oneshot::Sender<Result<(), E::Error>>)>, | ||
pub struct EntityRef<I, E, S, T, Tail> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will these types never end up in user code? How do you pass around these refs if you cannot reasonably type them out any more?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EntityRef<Uuid, Evt, Counter, Decrease, Cmds<Increase, ()>
is how this type looks like in the example. I agree that this is ugly, but users can make a type alias once. And I plan to create a type macro which can be used to ease making the type alias, something like:
type CounterEntityRef = EntityRef!(Counter, Uuid, Evt, Increase, Decrease)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 indeed, that's not too bad, a bit weird how the list of commands needs to be encoded, but maybe ok enough? Is there an implementation of a coproduct in Rust which we could reuse?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
frunk has a coproduct
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neat, will give it a try.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good.
Actually to define the entity, there is not more boilerplate. The examples written in the new way have about the same number of lines of code, including the now possible individual errors and replies. And here comes the best: You can still apply the old style by just defining a single command (enumeration). |
06fe8b8
to
30614c5
Compare
True, the old |
fn handle_stringly_things(co: Coprod!(&'static str, String)) -> String {
co.fold(hlist![
|s| format!("&str {}", s),
|s| format!("String {}", s),
])
} |
Wait until state becomes more (an enum) than a simple struct (like in the Counter example). Then you will get your pattern matching ;-) |
920e6f5
to
0f6f3c7
Compare
f48a677
to
89b8c9b
Compare
No description provided.