[Issue 1983] Delegates violate const

d-bugmail at puremagic.com d-bugmail at puremagic.com
Fri Jan 22 22:27:03 UTC 2021


https://issues.dlang.org/show_bug.cgi?id=1983

Bolpat <qs.il.paperinik at gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |qs.il.paperinik at gmail.com

--- Comment #24 from Bolpat <qs.il.paperinik at gmail.com> ---
(In reply to anonymous4 from comment #21)
> Nice progress. New test case:
> ---
> struct A
> {
>     void delegate() a;
>     int b;
>     void f(){ a=&g; }
>     void g(){ b++; }
>     int h() const { a(); return b; }
> }
> 
> void f(ref const A a)
> {
>     const int b1=a.h, b2=a.h;
>     assert(b1==b2,"changed");
> }
> 
> unittest
> {
>     A a;
>     a.f();
>     f(a);
> }
> ---

I fail to see how this is a problem. Const correctness isn't as strong as you
think it is. You're conflating const and immutable in a non-obvious way.
First, consider that the unittest's variable `a` is mutable, so (this is
important!) the free function `f` cannot expect its parameter `a` not to change
when doing anything. One usually thinks that aliasing is necessary for that
(and even here, aliasing occurs, its just rather hidden), but because `f` only
takes one `const` parameter and is factually pure (annotate all functions and
the unittest `pure` if you like, it compiles, I tried).
What you do by calling `a.f()` in the unittest, is creating a mutable reference
to `a` in the context pointer of `A.a` (why TF did you have to use names
multiple times??). In the const method `h`, the delegate `a` is const which
means you cannot assign it like in `A.f`, but calling it is okay. This way,
using its mutable context pointer, it mutates the underlying object.
While it looks like a `const` method mutates the object, this isn't a const
violation.

One could argue that the context pointer in a delegate is part of it. Viewing a
delegate as a pair (void function(ref Context, ...) fp, Context* ptr) where
Context is a suitable struct holding the contents of the context, ptr is
transitively part of the struct and in a const method, must be const.

If this were an issue of const only, but not immutable, this bug report would
be invalid.

HOWEVER, this can be rephrased in a completely pure/immutable style. Immutable
means much more than const. It is much easier to spot violations of it, since
any change is one.

I made a version of the quoted code that clearly violates immutable:

    struct A
    {
        void delegate() pure dg;
        int value;

        this(int value) pure
        {
            this.value = value;
            this.dg = &this.mut;
        }

        void mut() pure { ++value; }

        int kaboom() pure const
        {
            dg();
            return value;
        }
    }

    void f(ref const A x) pure
    {
        immutable int v1 = x.kaboom;
        immutable int v2 = x.kaboom;
        assert(v1 == v2, "changed"); // fails
    }

    void main() pure
    {
        immutable A a = immutable(A)(0);
        f(a);
        // usually fails, but might pass due to optimization:
        assert(a.value == 0, "changed");
    }

It's even hard to pin-point which exact part of the code should be an error.

--


More information about the Digitalmars-d-bugs mailing list