Hacker News new | ask | show | jobs
by qppo 2200 days ago
Here's some generic code I wrote in Rust recently. I had two unrelated iterators/collections and I needed to flatten and sort them into a single buffer.

    struct Data {
        idx: usize
        // ... 
    }
    
    struct Foo {
        stuff: Vec<Vec<Data>>
    }

    
    struct Bar {
        stuff: Vec<Data>
    }


    fn flatten_and_sort (foo:Foo, bar:Bar) -> Vec<Data> {
        let mut output = 
            foo.stuff.into_iter()
               .flat_map(|v| v.into_iter())
               .chain(bar.stuff.into_iter())
               .collect::<Vec<_>>();

        output.sort_by(|lhs, rhs| lhs.idx.cmp(&rhs.idx));
        output
    }
Now you could argue that this is just "generics for collections" but the way those iterator combinators are written make heavy use of generics/traits that aren't immediately applicable for collections. Those same combinator techniques can be applied to a whole host of other abstractions that allow for that kind of user code, but it's only possible if the type system empowers library authors to do it.
2 comments

You can actually use the power of generics to get rid of the two inner calls to `into_iter()`:

    let mut output: Vec<_> =  
        foo.stuff.into_iter()
            .flat_map(|v| v)
            .chain(bar.stuff)
            .collect();
I believe you can just use `.flatten()` instead of `.flat_map(|v| v)`:

    let mut output: Vec<_> =  
        foo.stuff.into_iter()
            .flatten()
            .chain(bar.stuff)
            .collect();
I might make it slightly more clear what the intent is by doing this:

    let mut output: Vec<_> =
        Iterator::chain(foo.stuff.into_iter().flatten(), bar.stuff)
            .collect();
But still basically the same.
Yes, functional programming patterns are nice. It's possible to write that even more concisely in JavaScript.