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