logical const without casts!

Christophe travert at phare.normalesup.org
Fri Sep 30 17:56:11 PDT 2011


"Steven Schveighoffer" , dans le message (digitalmars.D:145867), a
 écrit :
> But ref int _i is the parameter to the constructor.  Here is where your  
> proposal breaks down.
> 
> It's entirely feasible for class Foo to be compiled *separately* from the  
> module that contains globalFoo.  And it's also possible that when  
> compiling the above line, the language *does not have* access to the  
> source code of the constructor.  How does it know that _i gets put into a  
> const delegate?
> 
> Likewise, when compiling Foo, how does the compiler know that the  
> constructor is being used to cast to immutable?  I just don't think there  
> is enough information for the compiler to make the correct decision.

You say it is impossible for the compiler to check the constness of the 
arguments passed to the constructor ?
Well, allow me to doubt your statement, because my compiler can (it is 
gdc 4.4.5 using dmd 2.052).

Easy test, with a pointer instead of a delegate:

struct Foo
{
  int* _i;
  ref int i() { return *_i; }
  this(int* m_i)
  { _i = m_i;  }
  this(const int* m_i) const
  { _i = m_i; }
  this(immutable(int)* m_i) immutable // change immutable attribute of
        // the constructor and main won't compile.
  { _i = m_i; }
}

void main()
{
  int ma;
  Foo mfoo = Foo(&ma);
  const int ca;
  const Foo cfoo = Foo(&ca);
  immutable int ia;
  immutable Foo ifoo = Foo(&ia);
}

Now try to remove the const or the immutable attributes in the different 
this(int*) overload. You can play and try many changes, if you find a 
way to put an immutable int inside a mutable Foo, you get a banana for 
having found a great hole in the langage (or at least in the compiler).

Protect can (and has to!) be assured for a simple pointer.
Why would it not be the case with a delegate context pointer ?

Now the full test with delegate:

module a;

struct B
{
  int* _b;

  this(int* m_b) { _b = m_b; }
  this(const(int)* m_b) const { _b = m_b; }
  this(immutable(int)* m_b) immutable { _b = m_b; }

  int* b() { return _b; }
  const(int)* b() const { return _b; }
  immutable(int)* b() immutable { return _b; }
}

struct Foo
{
  int* delegate() _i;
  ref int i() { return *_i(); }
  this(int* m_i)
  {
    B b = B(m_i);
    _i = &b.b;
  }
  this(const int* m_i) const
  {
    const B b = B(m_i);
    _i = &b.b;
  }
  this(immutable int* m_i) immutable
  {
    immutable B b = B(m_i);
    _i = &b.b;
    // try to uncomment the following line:
    //    _i = () { return m_i; };
  }
}


module test;
import a;

void main()
{
  int ma;
  Foo mfoo = Foo(&ma);

  const int ca;
  const Foo cfoo = Foo(&ca);

  immutable int ia;
  immutable Foo ifoo = Foo(&ia);
}


To know why I created the struct B, try to uncomment the 
line I indicated in a.d and compile. What do you discover ?

a.d:34: Error: cannot implicitly convert expression (__dgliteral1) of 
type immutable(int*) delegate() to immutable(int* delegate())

So the type I thought I was proposing, the const or immutable delegate 
that protects its context pointer already exists in my compiler. The 
only problem is that at the moment, you have to use an helper structure 
to create this type of delegate...

> What if it has no access to the delegate creation code?  How does it  
> disallow it?

The compiler cannot cast a newly constructed structure to immutable if 
it cannot access the creation code, unless the creation code is marked 
immutable (and then there is actually no cast to do).


Me thinking I could improve the langage... Well, the conversation was 
interesting and I learned a lot about d today.

-- 
Christophe


More information about the Digitalmars-d mailing list