On Mon, Jul 29, 2019 at 05:32:58PM +0000, Matt via Digitalmars-d-learn wrote: > I've noticed that for some ranges in Phobos empty is marked const > (e.g. iota) but for other ranges (e.g. multiwayMerge) it is not > const. Is there a reason why? Isn't empty guaranteed not to alter the > data of the range and so should be const?
Although .empty should be *logically* const, some ranges do non-const work in .empty for various reasons (e.g., caching, lazy evaluation, etc.). Since D doesn't have logical const, it can't be used in every case. > This is causing me considerable headaches as I try to write my own > ranges that accept other ranges and have it all work for the general > case. Any advice would be welcome. Generally, the idiom is to let the compiler do attribute inference by templatizing your code and not writing any explicit attributes, then use unittests to ensure that instantiations of the range that ought to have certain attributes actually have those attributes. For example, instead of writing: struct MyRange(R) { ... @property bool empty() const { ... } ... } write instead: struct MyRange(R) { ... // No attributes: compiler does inference @property bool empty() { ... } ... } // unittest ensures .empty is callable with const object. unittest { const rr = MyRange!(const(Range))(...); assert(rr.empty); // will fail compilation if .empty is non-const } The unittest tests that a specific instantiation of MyRange has const .empty. It's still possible to use MyRange with a range that has non-const .empty, but this unittest ensures that the non-const-ness wasn't introduced by the implementation of MyRange itself, but only comes from the template argument. T -- "Holy war is an oxymoron." -- Lazarus Long