Skip to content
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

Merged
merged 18 commits into from
Mar 15, 2024
Merged

chore: rewrite api #192

merged 18 commits into from
Mar 15, 2024

Conversation

hseeberger
Copy link
Owner

No description provided.

@hseeberger hseeberger self-assigned this Mar 8, 2024
@hseeberger hseeberger force-pushed the chore/rewrite-api branch 2 times, most recently from 27b1509 to e156e83 Compare March 10, 2024 08:37
Copy link
Collaborator

@jrudolph jrudolph left a 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 EntityRefs 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).

E: EventSourced,
{
cmd_in: mpsc::Sender<(E::Cmd, oneshot::Sender<Result<(), E::Error>>)>,
pub struct EntityRef<I, E, S, T, Tail> {
Copy link
Collaborator

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?

Copy link
Owner Author

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)

Copy link
Collaborator

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?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

frunk has a coproduct

Copy link
Owner Author

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.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good.

@hseeberger
Copy link
Owner Author

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).

@hseeberger hseeberger force-pushed the chore/rewrite-api branch 2 times, most recently from 06fe8b8 to 30614c5 Compare March 11, 2024 12:35
@jrudolph
Copy link
Collaborator

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).

True, the old Eventsourced style also had its drawbacks. The new style feels a bit like implementing commands the OOP way which is workable but maybe not what you would expect when you also have pattern matching and enums in the language.

@jrudolph
Copy link
Collaborator

pattern matching and enums in the language

frunk::Coproduct has fold which offers pattern-match-y syntax:

fn handle_stringly_things(co: Coprod!(&'static str, String)) -> String {
    co.fold(hlist![
        |s| format!("&str {}", s),
        |s| format!("String {}", s),
    ])
}

@hseeberger
Copy link
Owner Author

True, the old Eventsourced style also had its drawbacks. The new style feels a bit like implementing commands the OOP way which is workable but maybe not what you would expect when you also have pattern matching and enums in the language.

Wait until state becomes more (an enum) than a simple struct (like in the Counter example). Then you will get your pattern matching ;-)

@hseeberger hseeberger force-pushed the chore/rewrite-api branch 4 times, most recently from 920e6f5 to 0f6f3c7 Compare March 14, 2024 07:26
@hseeberger hseeberger merged commit 03a0238 into main Mar 15, 2024
7 checks passed
@hseeberger hseeberger deleted the chore/rewrite-api branch March 15, 2024 09:18
@github-actions github-actions bot mentioned this pull request Mar 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants