3 ms·
I don't understand why the lazy algorithms aren't enough. Can't we have an assignment to vectors from lazy streams, or constructors from them? Why can't the
by repsilat 12y ago
I don't understand why the lazy algorithms aren't enough. Can't we have an assignment to vectors from lazy streams, or constructors from them?
Why can't the
std::vector<int> ints =
read_ints() | cont::sort | cont::unique;
from TFA can't be done "as lazily as possible" (i.e., sort eagerly and uniq lazily). Alternatively, something like
std::vector<int> ints(read_ints() | cont::sort | cont::unique);
or even
std::vector<int> ints;
read_ints() | cont::sort | cont::unique > ints;
What reason could we have for making `read_ints` and `unique` eager by default?
Performance-wise, the lazy filter works in constant space, will result in fewer dcache misses if the data set is large, and (I think) provides more opportunity for the optimizer to do clever things. The eager chain may have better icache performance if the filter is very complicated.
And it's easy to go from lazy to eager -- just put everything in a vector. If you want to go from eager to lazy, though, you're out of luck.
- zamalek 12y agoI think it comes down to a "memory bug" vs. "performance bug" trade-off. If you make it default-lazy you run the risk of having the stream evaluated multiple times. If you make it default-eager you run the risk of O(N) memory (as you said). I agree with your side of the trade-off, a performance bug (result: slow application) is always preferable to a memory bug (result: failed malloc, likely crash) in production. To make things more desirable, you could always do something even simpler than your example: auto ints = read_ints() | cont::sort | cont::unique | cont:to_vector; That way fixing the performance bug would only need a one-liner. Still, having the option is better than nothing.
- eric_niebler 12y agoIn my experience, it's really important to be able to look at some code and know its performance characteristics: does it allocate memory? Who is managing the lifetime of the objects and how many times are the elements copied/moved? How many passes over the data are made? The separation of eager from lazy adaptors makes it possible to know those performance characteristics at a glance. Looking at your code: std::vector<int> ints; read_ints() | cont::sort | cont::unique > ints; If `cont::unique` is lazy (non-owning), what is the lifetime of the elements allocated by `cont::sort` (or moved from `read_ints()`)? If the code had been written instead like below, who is responsible for keeping the elements alive? std::vector<int> ints; auto tmp = read_ints() | cont::sort | cont::unique; tmp > ints; There's a whole host of issues here that you're not dealing with.