Skip to content

Folds are not implemented for &hlist and &mut hlist #180

@ImmemorConsultrixContrarie

Description

Reasons to have it

The main reason to have it is performance.

  1. Destructing HCons<H, T> into H and T copies both H and T.
  2. 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 ?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions