this post was submitted on 12 Jul 2025
14 points (100.0% liked)

Rust

7158 readers
32 users here now

Welcome to the Rust community! This is a place to discuss about the Rust programming language.

Wormhole

[email protected]

Credits

  • The icon is a modified version of the official rust logo (changing the colors to a gradient and black background)

founded 2 years ago
MODERATORS
 

An interesting article that lays out a problem and goes through a few different solutions, some of which I haven't thought about much before.

I'm working on a video game in Rust, and I'm running into this kind of modelling problem when it comes to keeping track of the game state. So far I've refactored something that resembles Approach 5 into something that looks more like Approach 3. As I get more confident about the final shape of the data, it (seemingly) becomes a better idea to represent it in a more structured way.

top 6 comments
sorted by: hot top controversial new old
[–] [email protected] 2 points 1 day ago

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

[–] [email protected] 6 points 1 day ago (1 children)

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.

[–] [email protected] 2 points 1 day ago

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

[–] [email protected] 3 points 2 days ago (1 children)

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?

[–] [email protected] 2 points 1 day ago* (last edited 1 day ago)

It's approach 2

[–] [email protected] 6 points 2 days ago* (last edited 2 days ago)

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.