Should the "front" range primitive be "const" ?

Jonathan M Davis newsgroup.d at jmdavisprog.com
Wed Jan 31 01:05:47 UTC 2018


On Tuesday, January 30, 2018 07:49:28 H. S. Teoh via Digitalmars-d-learn 
wrote:
> On Tue, Jan 30, 2018 at 08:54:00AM -0500, Steven Schveighoffer via 
Digitalmars-d-learn wrote:
> > On 1/29/18 8:20 PM, Jonathan M Davis wrote:
> [...]
>
> > > If you want to put an attribute on it, inout is better, because then
> > > it will work with any constness, but in general, I'd suggest just
> > > avoiding the use of const or immutable altogether when dealing with
> > > ranges. front can return a const element, and that will happen if
> > > you use auto and whatever you're wrapping is const, but const ranges
> > > are utterly useless, because they can't be mutated and thus can't be
> > > iterated. As such, almost no code is ever going to have a range that
> > > is anything but mutable, which means that having front be anything
> > > but mutable is generally pointless.
>
> I think you're conflating a const range, which *is* pretty useless since
> you can't iterate it, and a const .front, which only means "calling
> .front will not change the state of the range".  The latter is very
> possible, and potentially useful.  Well, there's also a .front that
> returns a const element, which means "you can't change the current
> element of the range". That's also possible, and useful.

Except that unless front returns by ref, it really doesn't matter whether
front is const unless it's violating the range API, since front is supposed
to return the same value until popFront is called (or if it's assigned a new
value via a front that returns by ref). So, in practice, putting const on
front really doesn't help you any, and it actually hurts you for range
composability.

> Simen has had some ideas recently about "head mutable" aka tail-const,
> which could be a first step towards making const ranges, or rather
> tail-const ranges, actually usable:
>
>   https://forum.dlang.org/post/cpxfgdmklgusodqouqdr@forum.dlang.org
>
> tl;dr summary:
>
> (1) Ranges implement a standard method, tentatively called
>     opHeadMutable, that returns a head-mutable version of themselves.
>     For example, const(MyRange!T).opHeadMutable would return
>     MyRange!(const(T)).
>
> (2) Standard library functions would recognize opHeadMutable and use it
>     where needed, e.g., when you hand them a const range.
>
> (3) Profit. :-P

I still need to look over what he's proposing in more detail - it's been
proposed before (by Andrei IIRC) that one possible solution would be to add
an operator for returning a tail-const version of a type, but no one has
ever taken that idea anywhere.

Personally, I'm getting to the point that I'd rather just avoid const than
deal with any further complications for ranges. In principle, I like the
idea of const, but in practice, it just constantly gets in the way, and I've
rarely actually seen any benefit from it in either C++ or D. I can think of
one time in my entire life where const has prevented a bug for me - which
was when I got the arguments backwards to C++'s std::copy function.

At least with immutable, you get implicit sharing and some optimization
opportunities. In principle, const can get you some of the optimization
opportunities but only in really restricted circumstances or circumstances
where you could have used immutable and the code would have been the same
(e.g. with int).

- Jonathan M Davis



More information about the Digitalmars-d-learn mailing list