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

H. S. Teoh hsteoh at quickfur.ath.cx
Fri Feb 2 14:29:34 UTC 2018


On Fri, Feb 02, 2018 at 07:06:56AM +0000, Simen Kjærås via Digitalmars-d-learn wrote:
> On Thursday, 1 February 2018 at 18:58:15 UTC, H. S. Teoh wrote:
> > However, if we go back to the idea of tail-const, we could
> > potentially eliminate the need for casts and also avoid breaking
> > immutable.  Basically, the problem with writing const(RefCounted!T)
> > is that it's a one-way street: on the scale of increasing
> > restrictiveness, we have the series:
> > 
> > 	RefCounted!T < RefCounted!(const(T)) < const(RefCounted!T)
> > 
> > Once you've gone all the way down to const(RefCounted!T), you can no
> > longer safely back out to RefCounted!(const(T)).
> > 
> > So that means we want to avoid const(RefCounted!T) completely.
> 
> I'm not really saying I disagree with that, but it's just not
> realistic.  Which code would you rather write?
> 
> void foo(T)(const T t) {}
> foo(myValue);
> 
> or:
> 
> void foo(T)(T t) if (isTailConst!T) {}
> foo(myValue.tailConst);
> 
> The beauty of .headMutable is it generally doesn't affect user code.
> If we have to tell people not to use const(T) because its semantics
> are broken, we've failed.

Its semantics are not broken; it's just harder to use. Due to const
transitivity, it's an all-or-nothing deal.  .tailConst gives us the
middle ground.


> Now, if at any point in your program you have an
> immutable(RefCounted!T), something's gone horribly wrong - basically
> all of the RefCounted's semantics break down when it's immutable, and
> any attempt at fixing it is undefined behavior. I think we can safely
> disregard the problems of immutable(RefCounted!T).

Immutable may be useless for RefCounted, but I'm thinking of containers
and wrapper types in general. Today, due to ranges being basically
useless when you can't mutate them, you're forced to choose between a
completely mutable range, or no range at all. Having .tailConst as a
standard construction lets you create a usable range that provides a
compiler-verified guarantee that nobody will be able to modify range
elements. Today we don't have a standard way of doing this, and so
people have given up on using const with ranges. We're missing out on
the guarantees that const provides. .tailConst lets us get some of those
guarantees back without requiring us to tie our hands behind our backs.


> Once we've defined immutable(RefCounted!T) to be undefined behavior,
> suddenly casting from const(RefCounted!T) to RefCounted!(const(T)) is
> OK again.
[...]

The problem with this is that we're now relying on convention rather
than something that can be statically verified by the compiler. Once you
allow casting away const, there's no longer a guarantee that somebody
didn't pass in an immutable, whether by mistake or otherwise. We know
from C/C++ where programming by convention leads us. :-P


T

-- 
Having a smoking section in a restaurant is like having a peeing section in a swimming pool. -- Edward Burr 


More information about the Digitalmars-d-learn mailing list