Fully transitive const is not necessary

Sean Kelly sean at invisibleduck.org
Thu Apr 3 11:00:50 PDT 2008


== Quote from Sean Kelly (sean at invisibleduck.org)'s article
> == Quote from Walter Bright (newshound1 at digitalmars.com)'s article
> > Sean Kelly wrote:
> > > My traditional argument in support of logical const is this:
> > >
> > >     class C
> > >     {
> > >         mutable mutex monitor;
> > >         std::string name;
> > >     public:
> > >         std::string name() const
> > >         {
> > >             scoped_lock sl( monitor );
> > >             return name;
> > >         }
> > >
> > >         void name( std::string const& n )
> > >         {
> > >             scoped_lock sl( monitor );
> > >             name = n;
> > >         }
> > >     };
> > >
> > > Here, the mutex has nothing to do with the state of the object and
> > > must be modified even during logically non-modifying operations.
> > > Similar behavior might be necessary for a logging system in some
> > > instances, etc.  However, I'm not certain whether this is sufficient
> > > to justify logical const in general.  As you say--it has some serious
> > > problems as well.
> > If C.name were invariant, there would be no need for any locks. I don't
> > think this is a good example, because with D's invariant strings there
> > is no need for such locking.
> I'm not sure that's true.  Mutexes do two things: first, they guarantee
> atomicity for an arbitrary sequence of instructions and second, they
> provide a memory barrier so the result of those instructions is made
> visible to any other thread which later acquires the same mutex.  The
> invariant label provides a slightly different guarantee: that the data
> underlying an invariant reference will not ever change.

I realized that I didn't mention it in this message so I wanted to follow up.
>From my perspective, the advantage of invariant strings are that the user
doesn't have to worry about COW or anything like that because the duping
is done up front.  So:

    class Person
    {
        private string m_name;
        void name( string n ) { synchronized m_name = n; }
        string name() { synchronized return m_name; }
    }

If m_name were not invariant, the code would have to look like this to
guarantee safety:

    class Person
    {
        private char[] m_name;
        void name( string n ) { synchronized m_name = n.dup; }
        string name() { synchronized return m_name.dup; } // added .dup
    }

Without the explicit copying, the creator of Person would have to rely on
documentation to enforce ownership rules (ie. that passing a string to
Person.name indicates a transferral of ownership and that the user should
not retain a reference to this buffer or modify it after the transfer takes place)
because there's no way to indicate them in code in D.  In C++, as I'm sure
you're aware, std::auto_ptr is used to indicate transfer of ownership for
dynamic data, or plain old pass by value is used instead.


Sean



More information about the Digitalmars-d mailing list