Fully transitive const is not necessary

Koroskin Denis 2korden+dmd at gmail.com
Wed Apr 2 06:31:01 PDT 2008


On Wed, 02 Apr 2008 12:14:28 +0400, Janice Caron <caron800 at googlemail.com>  
wrote:

> On 01/04/2008, guslay <guslay at gmail.com> wrote:
>> What mutable does is allowing finer-grained control over the powerful  
>> const system. It does not weaken it, it controls its scope. Those are  
>> orthogonal issues (as far as I have yet to see an instance where having  
>> half the fields of an object const, instead of all the fields of the  
>> object, limits anything in any way).
>
> Really?
>
>     class C
>     {
>         int x;
>         mutable int y; // just pretend this is legal
>     }
>
>     void f(const(C) c)
>     {
>         int temp = y;
>         y = temp + 1;
>     }
>
> Now imagine two threads calling f simultaneously with the same c.
> Imagine a thread switch occurs between the two statements.
>

I like current const system, and I understand that it would help to do  
multiprogramming in D.

But maybe we sould look to the problem from different point.
The problem you have just shown doesn't correlate with const correctness.

Maybe we should introduce some other data status like 'concurrent' or  
'thread-safe' to determine that data can be accessed or method can be  
called with no side effects. It is _great_ contract which not only gives  
programmer additional guaranties, but it also helps compiler to make  
optimizations.

class C
{
    // Call this method as you wish, it's safe!
    // Author takes all the responsibility for its safety
    concurrent void f()
    {
        // ... some data manipulation, guarded by mutexes
    }

    // This method is concurrent, too
    // Compiler makes guaranty it's safe
    synchornized void g()
    {
    }
}


Neither programmer nor compiler can rely on method if it behaves like this:

class C
{
    int refCount = 0;

    void addRef()
    {
        ++refCount;  // not safe
    }
}

And we cannot mark the method 'pure'. Instead, we could mark it  
'concurrent':

class C
{
    int refCount = 0;

    // via 'synchronized' modifier
    synchronized void addRef()
    {
       ++refCount;
    }

    // or by hand
    concurrent void addRef_2()
    {
        while (true) {
           int refs = refCount;
           if (thread.atomic.cas(&refCount, refs, refs+1)) {
              break;
           }
        }
    }
}

Note that ALL pure methods are concurrent.

This way, we could allow mutable data, but only if _all_ access to it is  
passes through concurrent methods:

class Square
{
     private mutable int area;
     private int width;

     this(int width)
     {
        this.width = width;
        this.area = -1;      // ok, safe
     }

     invariant int getArea()
     {
        if (area == -1) {
           area = width*width;	// BAD
           // method cannot be marked as invariant, if it modifies mutable  
variables
        }
        return area;
     }

     invariant int getArea()
     {
        if (area == -1) {
           synchronized(this) {
              if (area == -1) {
                 area = width*width;	// OK now, no sife effects.
              }
           }
        }
        return area;
     }
}

Logical const _can_ be used with no sife effects, but programmer should  
pay attention to this kind of data.

Waht do you think?



More information about the Digitalmars-d mailing list