Why does `filterBidirectional` exist, and why isn't it called `filter`?
FeepingCreature
feepingcreature at gmail.com
Thu Mar 9 16:44:50 UTC 2023
On Thursday, 9 March 2023 at 13:16:07 UTC, Steven Schveighoffer
wrote:
> On 3/9/23 3:06 AM, FeepingCreature wrote:
>> Yes I know the stated reason, to save time initializing the
>> range in `filter`.
>>
>> You know what I did because we didn't know
>> `filterBidirectional` existed?
>>
>> I literally *walked the entire range* returned by `filter` to
>> find the last matching element.
>
> Why not `rng.retro.filter`?
`retro` changes the semantics of the range, which often
represents business data. Thinking about the underlying model is
complicated enough without throwing in "But consider: what if the
elements were in reverse order".
>
>> `filter` should expose `back`. By all means, let `back` lazily
>> initialize, but I don't understand how `filterBidirectional`
>> was ever considered acceptable. Since when do we sacrifice
>> ease of use for performance? I mean, since 2011 apparently. -
>> This is bad ergonomics, bad discoverability and bad API
>> design. `filterBidirectional` delenda est.
>
> This has been a constant debate -- should ranges be allowed to
> lazily initialize on the first call to front (or back)?
>
> I'd say no. back/front shouldn't be modifying operations. I
> dislike the idea of storing a "was initialized" flag and having
> to check that on every call.
>
> That being said, there's no formal requirement for it. It's
> just a convention I think Phobos should stick to for its
> included ranges.
>
> -Steve
Sure: so precompute both `back` and `front`, every `filter` call.
No caching. This isn't done right now because the language
presumes, arbitrarily, that you won't care about `back`. That's
what I meant by sacrificing convenience for performance. Just do
what `filterBidirectional` does, every time, and have the current
`filter` be the odd one out. `filterForward` or whatever.
(I think the best way to go, in truth, is to *preinitialize
front* and *cache back*. But that solution, much as I think it is
optimal for all involved interests, is very hard to love.)
That said, I think the range API has a fundamental problem here.
`filter` pre-initializes `front` on every access, because it
reasonably presumes that we will then want to query it. However,
it cannot rely on this. If we were *guaranteed* that every access
to `popFront` would alternate with at least one access to
`front`, and conversely `back` with `popBack`, we could just
reduce `popBack` to `nextRange.popBack` and do the rest of the
popping in `back`! Then in the fast case (one access to each, in
turn) we would not waste any check. And the actual `filter` call
would always be constant-time.
More information about the Digitalmars-d
mailing list