Coming from Scala world, I am used to use "sealed class" a lot. I think that's the feature I miss the most in Rust.
I am wondering whether someone has a good alternative.
Basically both traits and enum have drawbacks for my usual use case:
Traits:
No exhaustive pattern matching
All the complications of traits in rust... (unsized, trait object safety limitations, etc...)
Enums:
Syntax is absurd if you just want to wrap a type (enum MyEnum{ MyType1(MyType1), MyType2(MyType2)}})
Each variant isn't a type so you cant implement a trait for just a variant.
Implementing a trait for the enum (like to_string) has to done using a match block while I would rather implementing it for each variant separately.
You lose the nice monomorphization that can do with Traits
I am aware of some of the thing that make it easier (or will...):
sum_type crate. Far from solving all my problems and I really dont like macros that wraps a lot of code, it affects readability, tools behaviour, etc...
Enum variant types RFCs. Doesn't solve all my issue and add explicitely a restriction Variant types may not have inherent impls, or implemented traits
Is there someone else feeling the pain? Anyone having an alternative pattern?
This essentially does the same as a match, but it's possibilities aren't defined in a match block, instead they are defined as "whatever implements Implementors", and therefore the function in Implementorsbecomes your "match" case.
Note: untested, as this was written on the mobile page, and I can't be bothered to deal with the playground on mobile
I don't have a single use case, I feel like that's something I need very often.
Today for example I have started a project to collect metrics from different system.
This is meant to grow, have many different system and many different kind of events.
Obviously this won't compile, because all the traits I am returning. Those traits are not even object safe. Serde objects themselves are not object safe, you have to use erased-serde which fills like a big hack and would confuse even more my colleagues...
So 3 choices I can think of:
Make my trait object safe, box everything. Besides all the obvious complications, there's some negative effect on the rest of my code because in some scenarios I want to retrieve one specific events and the boxing is unnecessary. Designing for both scenarios complicates my code by a lot.
Have an enum containing all my events and enum of enums to be able to scale with many events; Define get_event_type_id at the enum level (which in my case is awkward because the type_id is deduce from the content); having this weird enum, that I was referring to
Redesign how collecting events works to use a visitor-like pattern. Won't go in details about that, Rust is not the problem here, it just that it make the code unnecessarily tightly coupled and makes it much less nicer for the consumer of the API.
If I had sealed trait or something similar almost all my problems are gone. I can return a sized type (because we know all the variants) which implements a trait. The trait is implemented per Event type (no awkward pattern matching like with enum).
What I want is a sum type (sized, like enum) that can implement a trait by forcing all its member to implement the trait.
Cherry on top, similar to traits, you can start do monomorphization and have zero cost abstraction. All the benefits of both traits and enums in one....