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

Why marker types and not concrete values? #7

Open
sunshowers opened this issue Feb 1, 2024 · 0 comments
Open

Why marker types and not concrete values? #7

sunshowers opened this issue Feb 1, 2024 · 0 comments

Comments

@sunshowers
Copy link
Collaborator

sunshowers commented Feb 1, 2024

Our current model is what I'd refer to as the "marker model":

struct TypedUuid<T> {
    uuid: Uuid,
    marker: PhantomData<T>,
}

One kind of type that isn't representable in the marker model is a UUID that's "either this or that".

For example, you could imagine something like this, which I'll call the "concrete model":

struct TypedUuid<T> {
    uuid: Uuid,
    type_info: T,
}

enum FooOrBar {
    Foo,
    Bar,
}

impl TypedUuidKind for FooOrBar {
    fn tag(&self) -> TypedUuidTag {
        // match on self.type_info
    }
}

While the concrete model is more flexible, it also carries some rather large downsides. The main one is that it complicates our APIs. For example, for an ergonomic API we'd need

impl<T: TypedUuidKind> TypedUuid<T> {
    pub fn new_v4() -> Self where T: Default {
        Self { uuid: Uuid::new_v4(), type_info: T::default() }
    }

    pub fn new_v4_with_info(type_info: T) -> Self {
        Self { uuid: Uuid::new_v4(), type_info }
    }
}

Similarly, the concrete model would also complicate the FromStr impl, for which we have two options:

  • Restrict it to T: Default.
  • Require that the input string specify a tag, which is a pretty large behavior change that can break lots of things if not done with care.

The GenericUuid trait becomes more complex as well -- part of the benefit of the marker model is easily being able to write code that's generic over typed and untyped UUIDs. It's not clear how well that would survive in the concrete model.

Furthermore, the same result can be achieved in other ways most of the time -- users can just as well write their own enums "outside" the type param:

enum FooOrBarUuid {
    Foo(TypedUuid<Foo>),
    Bar(TypedUuid<Bar>),
}

And that would in many ways provide more clarity than putting the param inside the UUID. This approach would also let more data be associated with each variant, which is often required in practice.

Based on all this I'd like to keep the current marker model for now, and see how things evolve in the future.

@sunshowers sunshowers changed the title Why marker types and not a concrete value? Why marker types and not concrete values? Feb 1, 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

No branches or pull requests

1 participant