Refactor library to use type kinds for non-overlapping traits #2
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
One of the things I don't really like about my current implementation is the approach to generic impls of non-overlapping types. The approach of "wrap the type in another type so we can write generic implementations" like
recapn::field::Enum<Foo>
orrecapn::field::Struct<Bar>
is just really annoying in practice since you have to import these types in order to access the trait implementation that is generic for those types. This forces me to make concessions likeread_as_struct::<T>()
which just callsread_as::<field::Struct<T>>()
so you don't have to import the type.This PR is an alternative approach that uses a trait with an associated type to make non-overlapping generic implementations. It works really great in all the ways you would expect! Now we don't need
read_as_struct
, you can justread_as::<T>()
and it automatically selects the struct read implementation. You can have alist::Reader<Foo>
and alist::Reader<Bar>
and it will automatically be an enum, struct, or capability list based on the traits implemented by the types. Awesome!But there's one small hinge that doesn't make this perfect: rust-analyzer doesn't understand it. RA will give you completions for structs that it can know the type for, but it can't give completions for accessors.
While it can figure out what you want from a
read_as::<StructType>()
, it doesn't know what the result ofread_as::<List<StructType>>()
is.It gives errors saying you haven't implemented all match arms when you've definitely implemented all match arms. This is likely because it can't figure out what the types are supposed to be for some of said arms.
All in all, while it's great on the surface, since it doesn't work with the dev tools most people use I'm hesitant to go forward with it since it will make devex worse by getting rid of completions and type hints in many places where they currently exist today. Though I'm putting up the PR for comments and I'm hoping that one day RA can figure out what these types are. Then we can move forward with it since the experience will become better. Maybe someone with experience debugging RA will be able to use this too.