-
Notifications
You must be signed in to change notification settings - Fork 64
Description
Reasons to have it
The main reason to have it is performance.
- Destructing
HCons<H, T>
intoH
andT
copies bothH
andT
. - Destructing
&HCons<H, T>
into&H
and&T
involves only pointer arithmetic with constants and one pointer copy.
hlist.to_ref().fold() // create a new hlist with a bunch of pointers, then destruct it.
(&hlist).fold() // pointer arithmetic
The compiler might optimize both lines into the same binary code, or it might not.
Problems
The biggest problem will be UX. Right now HCons
and HNil
have nice methods foldl
and foldr
, and to use those methods the user doesn't have to import any traits.
With three fold impls for hlist
, &hlist
and &mut hlist
, there should be either no method on the struct itself, or three methods with different names, kinda like into_iter()
, iter()
and iter_mut()
.
Also, there will be some inconsistency between folds and other things like HMappable
, which will be implemented for by-value hlists only; though HMappable
could be implemented with foldr
, and the usefulness of this trait is a bit questionable. IntoReverse
could be implemented with foldl
. ToRef
and ToMut
could be implemented with foldr
.
Problems of not having those impls
Some libraries may use hlist instead of tuples with
impl_trait_for_tuples!(A, B, C, /* … */);
to make compilation time a bit better, or to avoid some unnecessary unsafe
in those impls (because hlist could be folded, while tuple could not be).
However, generic bounds without fold impls for &hlist
and &mut hlist
could be messy (or won't compile at all without some serious thinking):
UserHlist: HFoldLeftable<ByValFolder, ValAcc> + for <'a> ToRef<'a>,
for <'a> <UserHlist as ToRef<'a>>::Output: HFoldLeftable<ByRefFolder, RefAcc>,
Then, the library will write its own HFoldLeftable
(or HFoldRightable
) due to either performance or generic problems. However, if every such library would write its own folding trait, the user who will try to use both of those libraries in the same function will have to write a bit of boilerplate:
fn foo<H>(h: &H)
where &H: lib1::HFoldLeftable<Folder, Acc> + lib2::HFoldLeftable<Folder, Acc>
{}
The traits are identical, but the user should write both of them in the bound *sad user noises*.
So, yeah, any thoughts about it, @lloydmeta, @ExpHP ?