Why in Phobos is empty() sometimes const and sometimes not

H. S. Teoh hsteoh at quickfur.ath.cx
Mon Jul 29 19:35:18 UTC 2019


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


More information about the Digitalmars-d-learn mailing list