Reasons to have it
The main reason to have it is performance.
- Destructing
HCons<H, T> into H and T copies both H and T.
- 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 ?
Reasons to have it
The main reason to have it is performance.
HCons<H, T>intoHandTcopies bothHandT.&HCons<H, T>into&Hand&Tinvolves only pointer arithmetic with constants and one pointer copy.The compiler might optimize both lines into the same binary code, or it might not.
Problems
The biggest problem will be UX. Right now
HConsandHNilhave nice methodsfoldlandfoldr, and to use those methods the user doesn't have to import any traits.With three fold impls for
hlist,&hlistand&mut hlist, there should be either no method on the struct itself, or three methods with different names, kinda likeinto_iter(),iter()anditer_mut().Also, there will be some inconsistency between folds and other things like
HMappable, which will be implemented for by-value hlists only; thoughHMappablecould be implemented withfoldr, and the usefulness of this trait is a bit questionable.IntoReversecould be implemented withfoldl.ToRefandToMutcould be implemented withfoldr.Problems of not having those impls
Some libraries may use hlist instead of tuples with
to make compilation time a bit better, or to avoid some unnecessary
unsafein those impls (because hlist could be folded, while tuple could not be).However, generic bounds without fold impls for
&hlistand&mut hlistcould be messy (or won't compile at all without some serious thinking):Then, the library will write its own
HFoldLeftable(orHFoldRightable) 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: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 ?