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

Reply via email to