Should the "front" range primitive be "const" ?
Steven Schveighoffer
schveiguy at yahoo.com
Thu Feb 1 01:33:49 UTC 2018
On 1/31/18 7:49 PM, Jonathan M Davis wrote:
> On Wednesday, January 31, 2018 11:58:38 Steven Schveighoffer via
> Digitalmars-d-learn wrote:
>> On 1/30/18 8:05 PM, Jonathan M Davis wrote:
>>> 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.
>>
>> Right, but that is the difference between a convention ("front is
>> supposed to...") vs. a compiler-enforced guarantee (modifying data by
>> calling a const-tagged front is a compiler error).
>>
>> If you are OK with conventions, you don't need const at all.
>
> Except that if you're the one writing the function and decided whether it's
> const or not, you're also the one deciding whether it returns by ref or not.
> Unless you're dealing with a reference type, and it doesn't return by ref,
> then const doesn't protect front at all. It just affects whether it can be
> called on a const range.
You are misunderstanding here. You don't put const on front for the
purpose of allowing const ranges (which are useless), what it does is
say that the compiler guarantees, *even if the range is mutable* that
front won't modify it.
That is, code like the following is rejected by the compiler:
int front() const { return ++val; }
In other words, it's a contract that you can read without having to
examine the code saying "this won't mutate the range".
Sure, you can document "front shouldn't modify the range", and use that
convention, but without const, the compiler doesn't care.
> If you're dealing with generic code, then you have less control, and const
> starts mattering more, since you don't necessarily know what type is being
> returned, and if you're returning front from an underlying range, you the
> choice of eixther returning it by value or returning it by auto ref in case
> the underlying range returned by ref and passing that refness on is
> desirable. But const also interacts far more badly with generic code,
> because the odds are pretty high that it won't work in many cases. So, while
> in principle, using const to actually have the guarantees is valuable, in
> practice, it isn't very viable, because D's const is so restrictive.
Technically, wrapping requires introspection. If you don't care about
forwarding the "guarantee" of constness, then you can just tag all your
functions mutable, but if you do care, then you have to introspect.
> Personally, I avoid const in generic code like the plague, because unless
> you've restricted the types enough to know what you're dealing with and know
> that it will work with const, the odds are quite high that you're writing
> code that's going to fall flat on its face with many types.
Indeed, it's not straightforward, if you have to deal with types that
aren't tagged the way they should be. In addition, const is not inferred
for templates like other attributes, so you can't rely on that either.
-Steve
More information about the Digitalmars-d-learn
mailing list