logical const is a subset of transitive const

Steven Schveighoffer schveiguy at yahoo.com
Fri Sep 14 06:47:09 PDT 2007


I had this idea last night.  Not sure if it is valid, my computational proof 
skills suck :)

If you define logical const as:

I can define an object that has members that will be permanently mutable. 
If this object is declared const, those members are still mutable, and I can 
call functions which only modify those members.  These members are said to 
not hold the state of the object, and so the object is still const, but 
logically const.

And you define transitive const as:

An object that is defined as const means that all members of the object are 
const, and all data that the object references through member pointers and 
references are const.

Now, I can implement an object in transitive-const-land that implements the 
same features as logically const.

Lets say the 'mutable' keyword indicates that a member of an object is 
permanently mutable.  For simplicity's sake, I'll define an object A which 
has two data members m_mutable, and m_normal.  m_mutable is declared 
'mutable', m_normal is not.  I can redefine this as a transitive-const 
object A' which has a sub-object B.  Object B contains m_normal, and A' 
contains m_mutable.

In addition to data members, A has member functions.  Some of these 
functions are declared 'const', meaning they do not modify any member 
variables that are not declared 'mutable'.  The other functions are not 
declared const.  Let's say I have 3 functions.  One function f_const() is 
declared 'const' and does NOT modify m_mutable.  Another function 
f_mutable() is declared 'const' and modifies m_mutable.  A third function 
f_nonconst() is not declared 'const' and modifies both m_mutable and 
m_normal.  In my new representation, f_const and f_nonconst go into B, and 
f_mutable goes in A', and is no longer declared 'const'.

If I say that the logically const version of A' is such that A' is not 
const, but B IS const, then I have the equivalent interface as I did when I 
was using object A, but in a transitive-const world.

Here is the code:

logically const world:
class A
{
   int m_normal;
   mutable int m_mutable;
   int f_const() const
   {
      return m_normal + m_mutable;
   }

   int f_mutable() const
   {
      return m_mutable += m_normal;
   }

   void f_nonconst()
   {
      m_mutable++;
      m_normal++;
   }
}

And in transitive-const land:

class Aprime
{
  int m_mutable;

  class B
  {
     int m_normal;
     int f_const() const
     {
        return m_normal + m_mutable;
     }

     void f_nonconst()
     {
        m_mutable++;
        m_normal++;
     }
  }

   int f_mutable() const
   {
      return m_mutable += m_normal;
   }

   // syntactic sugar
   alias m_b.m_normal m_normal;
   alias m_b.f_nonconst f_nonconst;
   alias m_b.f_const f_const;

   // const B m_b; // logically const version
   B m_b;  // non-const version
}

So,

Here is the kicker.  I can ALMOST implement exactly what I want using 
transitive const using templates, by defining the type of m_b in my template 
declaration.  However, I can't simply create a new logically const reference 
to an existing Aprime (even though they only differ by const-ness).  So this 
is where I would need help from the language developer (i.e. Walter).

All this could be implemented easily enough by the compiler, by allowing the 
keyword mutable, and having the compiler assume a similar structure (the 
structure doesn't have to be exactly implemented this way, it's just a 
proof).  Then, it could allow me to declare an object logically const by 
defining a new keyword.  I propose the keyword lconst.  Then, I would have 
to implement my A class as such:

class A
{
   int m_normal;
   mutable int m_mutable;
   int f_const() const
   {
      return m_normal + m_mutable;
   }

   int f_mutable() lconst // lconst needed or m_mutable can't be changed
   {
      return m_mutable += m_normal;
   }

   void f_nonconst()
   {
      m_mutable++;
      m_normal++;
   }
}

And then I can do things like:

A x = new A;
lconst(A) y = cast(lconst)x;
y.f_normal(); // error, y is lconst
y.f_mutable(); // ok
y.f_const(); // ok

and I can still define transitive const as:

const(A) z = cast(const)z;
z.f_normal(); // error, z is const
z.f_mutable(); // error, z is const
z.f_const(); // ok

OK, so does this all sound like a pipe dream?  I have no idea if this is 
valid, but it sounds right to me.  I think I covered all the bases...

-Steve 





More information about the Digitalmars-d mailing list