const(FAQ)

guslay guslay at gmail.com
Mon Mar 31 12:01:39 PDT 2008


I think we are agreeing on the benefits of "pure" methods.

But arguing that an immutable object is automatically thread-safe is simply not true under the current definition of const. It's an over-generalization. It's just one part of the puzzle.

A pure methods has to be const, but a const method is not implicitly pure.


Kevin Bealer Wrote:

> guslay Wrote:
> 
> > Kevin Bealer Wrote:
> > 
> > > guslay Wrote
> > > ... logical const ...
> > 
> > I still don't see how dividing a const composite object (ie a class) in two
> > separate parts (mutable and immutable) would prevent any optimization
> > or thwart future development.
> >
> > I can see the optimization benefit of an eventual pure qualifier. With no
> > possible side effects, it would allow crazy functional programming tricks
> > (reordering, parallel dispatch, memoizing).
> > 
> > But const (or invariant) doesn't mean pure. The following does compile, and
> > is bitwise const. It's legal and it's full of side effects.
> 
> But only because it reaches outside the object.  For safety / correctness, I could
> argue that if you want the "dim" data to be const, you need to declare it as such,
> or wrap it in an object and declare a const one of those, but I guess that's beside
> the point.
> 
> You may be right about optimization and purity.
> 
> > static int dim = 0;
> > class Vector
> > {
> >      public const int size()
> >      {
> >          return ++.dim;
> >      }
> > 
> >      public const void printElement( int i )
> >      {
> >          // print element i to stdout
> >      }
> > };
> > 
> > As opposed to pure function, the only "mathematical" guarantee that the
> > const qualifiers gives on a method is that its immutable bits will not be
> > modified. Nothing else. So what is the problem if I say that only half the
> > bits are immutable?
> 
> (You can, technically, by making half of the fields const individually.)
> 
> The question is, what does "const" mean -- if it means that all the bits are
> immutable, you get a certain benefit.  If it means that some of them are,
> you get a different benefit.  I think the idea is that the "all bits" guarantee
> is more useful for the purpose of reasoning about whether it is safe to call
> a method from inside / outside a locked / synchronized() section.
> 
> A normal .size() method will operate on the fields of the object in question.
> If it is const, it does not need to modify those fields.  This means that you
> can safely call such methods in parallel from multiple threads on the same
> object.  Is this an absolute guarantee?  No -- side effects as shown above
> break this assumption.  But only the external ".dim" field can be corrupted,
> and it should have its own object and/or locking if that is an issue.
> 
> But calling multiple non-const methods is not safe unless proper locking is
> performed.
> 
> Now here is the critical distinction:  this applies to the D concept of const,
> but not the C++ concept since mutable fields tend to reintroduce the need
> for locking even in the presence of C++ "logical const" correctness.
> 
> The caller may need to get locks when calling the callee's methods (if the
> callee does not do its own locking), but only for non-const objects.  If the
> callee does its own locking then another problems arises -- the caller must
> be careful of deadlock.  So you are hemmed in from both directions -- it
> is dangerous to do too much locking (due to deadlock) or too little (due
> to race conditions), which is why a compiler-enforced guarantee is useful.
> 
> In either case, knowing the object is const will be more useful if it is an
> enforced transitive const rather than a logical const, since the former
> implies something about the need for locking while the latter does not.
> 
> (Of course, this assumes again that const methods are pure, i.e. don't
> reach outside the object to change things in important ways.  It does
> require that much cooperation at any rate, although I guess I'm the
> one to suggest doing otherwise...)
> 
> > Const/invariant on data enables aggressive optimizations; const/invariant
> > on a method does not.
> 
> Probably true.
>  
> > Or am I missing something?
> 
> I think in C++ you have a kind of contract with the std library, other developers, etc,
> to not change the observable value of a const object so that it is different after the
> call than before it.  In D you have a similar contract not to change the bitwise value
> of the object.
> 
> In C++ this contract is non-enforceable -- if you make all the fields mutable, you
> have essentially discarded the const qualifier.  In D you have a different contract,
> to not modify the actual bits of an object.  This contract is enforceable and solid
> because the compiler can truly enforce it.
> 
> The code we've been discussing violates the (C++) contract in any case because
> it changes the conceptual value of the object from a const method.  The compiler
> can't enforce this because the ++.dim is indistinguishable from the ++ inside a
> buffered stream when you output a character, or any other external effects.  It
> doesn't violate the D "const contract", because the D contract talks about the bit
> state of this object (and no other) rather than the observable value.
> 
> D has a const contract that the compiler really can enforce, and do so completely,
> whereas C++ has a const contract that the compiler can't enforce.  It can make
> sure you fill out the proper paperwork when you ignore the contract, but it doesn't
> stop you from ignoring it.
> 
> Kevin
> 




More information about the Digitalmars-d mailing list