How to break const

Artur Skawina art.08.09 at gmail.com
Wed Jun 20 06:22:50 PDT 2012


On 06/20/12 09:31, Christophe Travert wrote:
> Artur Skawina , dans le message (digitalmars.D:170191), a écrit :
>>> The proper way to do this is not cast, it is to give the proper 
>>> constness for all types and methods :
>>>
>>>    struct S {
>>>       int i; this(int i) { this.i = i; }
>>>       T* p; 
>>>       void f(int i) const { this.i = i; /*p.i++;*/ }
>>> // the commented part is illegal because S.f is const
> 
> I missed that. Then I disagree with your use of delegates. The solution 
> here is to make the free f function to take a non const T*, since the 
> function tries to modify variables from that T instance (via a 
> delegate).

The issue is the delegate definition - what exactly is a delegate?
My first message in this thread started with this sentence:
"It's fine, if you view a delegate as opaque". Because if you do, then
accesses via a delegates context pointer are no different from using
an external reference. That message also contained a program to show
how trivial bypassing const is, at least for impure functions. So
banning "unsafe" delegates wouldn't really change the situation.

I could, in theory, agree with "fixing" the delegates, they can be used
to break the type system. (In more serious ways than discussed here; but
I'm trying to avoid talking about it, as I'd expect the proposed short-term
fixes, that would appear here, to be unacceptable). But let's assume that
the delegates are correctly typed (both signature and ctx). Now you would
need to have mutable overloads for many cases where 'const' and 'inout'
methods work now. There are other ways to bypass const if somebody really
wants to, so is the extra cost justified, and wouldn't it result in _more_
bugs due to the extra code required? The compiler would have to learn to
handle cases like this:

   struct S {
      int i; this(int i) { this.i = i; }
      void delegate(int i) dg;
      void f() inout { dg(i); }
   }

   void main() {
      int j;
      auto s = new S(42);
      s.dg = (int i){ j += i; };
      f(s);
   }

   void f(const(S)* s) { s.f(); }

which would be illegal. Because it could *potentially* be abused. Except you
can do that w/o ever using a delegate, so where's the gain?

"Pure" (in d-speak) const methods would benefit - yes; but is that enough?

> I don't mind if the delegate modify an S or a T instance: it should not 
> modify anything. You use a delegate to store an S structure that you can 
> modifiy in a const T. This is only one step to consider the following 
> acceptable:
> 
> struct T {
>   ref int delegate() _i;
>   this(int i_) { _i = () => i_ }
>   @property ref int i() const { return _i(); }
> }
> 
> void foo(const T*)
> {
>   T.i = 10;
> }
> 
> Would you say that this is not a problem, since you do not modify a T 
> instance with that delegate?
> 
> I prefer to legalise:
> struct T
> {
>   mutable int i; // makes modifying i legal, but prevent instanciating 
>                  // an immutable T and several optimizations
> }

struct T;
void f(const(T)*);
void g(T* t) { f(t); }

>> Language design is not a game of whack-a-mole, where you ban random
>> features left and right, because you think you've noticed a problem,
>> without properly identifying it nor spending even a single second
>> figuring out the implications.
> 
> I completely agree with that. And I'm fine with the current situation: 

That was a generic comment, btw; not a direct response to this thread.

> you trust the programmer not to use delegates to break the const system 
> until we have a proper system to deal with this (inference of constness 
> of delegates, for a start). But encouraging the use of delegates to 
> modify variables from a const instance seems wrong to me.

I don't think anybody suggested it's OK; I'd consider code like in my
example to be broken, because it's confusing and a const method may
not expect the object to change. But 'const' only gives you a R/O view,
it does *not* make the object immutable, unless you hold the only
reference. Which you can not assume to be true in general, except when
it's a new object, or otherwise tagged as 'unique'.

artur


More information about the Digitalmars-d mailing list