casting away const and then mutating
Steven Schveighoffer via Digitalmars-d
digitalmars-d at puremagic.com
Fri Jul 24 13:44:44 PDT 2015
On 7/24/15 4:20 PM, Timon Gehr wrote:
> On 07/24/2015 10:08 PM, Steven Schveighoffer wrote:
>>
>> We can start with "casting away const and mutating, even if you know the
>> underlying data is mutable, is UB, except for these situations:..."
>>
>> And relax from there.
>
> But what is the point?
The original PR is to add a const and immutable version of upperBound
and lowerBound to RedBlackTree.
Both of these functions are effectively const. But we must return a
range that matches the constancy of the tree itself.
So for example:
RedBlackTree!int m;
const RedBlackTree!int c = m;
auto x = m.upperBound(5); // should return range over mutable ints
auto y = c.upperBound(5); // should return range over const ints.
The chosen implementation was to cast away const inside the const
upperBound function, and run the mutable one, knowing that the actual
algorithm doesn't modify any data. But I objected saying that it's
better to run the code as const, and cast away const at the end in the
mutable version, since the compiler will then be mechanically ensuring
the const promise in the case of a const RedBlackTree.
The resulting discussion was that this is undefined behavior. But
upperBound itself isn't modifying any data, it's just restoring the
constancy of the range. But the range itself could potentially be used
to modify the data. It didn't seem to me like this should be undefined
behavior, since the compiler would have to make a very long connection
through the various calls in order to see that everything would be const.
inout would work perfectly here, except you can't create a custom struct
with an inout member that implicitly casts back to mutable/const/immutable.
So I don't know the answer. It seems very bad to cast away const to run
a complex algorithm without mechanical checking. But ironically, that
may be the only defined way to do it (aside from copy-paste
implementation, or using a templated implementation).
The advantage of simply clarifying the spec is that the current compiler
behavior (which should work) doesn't need to change, we just change the
spec.
Ideally, we should just fix the situation with tail-const and we could
have the best answer.
I think I'll give up on this argument. There isn't much use in putting
in a rule for the spec that covers over a missing feature that we will
likely add later.
Also, I just thought of a better way to do this that doesn't require any
casting.
Forget this thread ever happened :)
-Steve
More information about the Digitalmars-d
mailing list