This was a good blog post. I have started using approach #3 as well for just about every situation where I was originally planning on just using a enum type by itself. Inevitably I end up needing to apply shared state to all of my enums (create date, parent table ID, etc.) and this approach has really worked out very well.
You can also add some convenience functions for returning if the kind is one of the variants (ex: IsKeywordSearch
) to make if-statements easier to read (and a match on the type enum is overly verbose when you don't need the properties contained within the enum itself).
Rust
Welcome to the Rust community! This is a place to discuss about the Rust programming language.
Wormhole
Credits
- The icon is a modified version of the official rust logo (changing the colors to a gradient and black background)
To me, it seems like this article is overemphasizing code duplication as problematic. If multiple types of searches use some of the same fields, it's okay to just copy them to each search type that uses them. This also allows each search type to be independently updated later on to add additional fields or deprecate existing fields without affecting other search types.
Fields that should always exist together should probably be moved to a struct containing those fields, if there's some concept that encapsulates them. Paging fields, for example, that exist only on two of three variants can just live in their own struct, and those two variants can have fields of that type.
Code duplication is only really problematic when all duplicates need to be updated together every time. That does not seem to be the case here.
seems to me he's trying to be more general than the Search
example and considering that another complex project may actually have those problematic cases
i mean, he doesn't even dismiss the patterns with code duplication, just lists it as a drawback, which agrees with his conclusion that there's no one-size-fits-all solution
I only skimmed this. But my mind from the start immediately went to
struct CommonData {
// common fields
}
enum VariantData {
Variant1 {
// Variant1 specific fields
},
// same for other variants
}
struct Search {
common: CommonData,
variant: VariantData,
}
but I reached the end and didn't see it.
Isn't this the way that comes to mind first for others too?
It's approach 2
one that i’ve used in the past but isn’t mentioned here is type state based. when developing a file upload service i have a File
struct with different states that implement FileState
, ie struct File<TState: FileState>
. Uploading
, Staged
, and Committed
. Uploading
contains a buffer and some block IDs, Staged
has no buffer but includes the block IDs, and Committed
is just a marker. they can have different methods based on their type state like impl File<Uploading>
. this gives us the type safety of, for example, not allowing a partially uploaded file to be committed, while still sharing some state like ID, etc.