oxidecomputer / oxidecomputer/newtype-uuid
Why marker types and not concrete values?
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 44
- Forks
- 10
- PR merge metrics
- No merged PRs in 30d
Description
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.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
No files, tests, or entry points are mentioned. Read the issue's marker-versus-concrete model discussion first; there is no defined implementation target or completion criterion, and the issue records a decision to keep the marker model.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 15/100