Topic: proposal to extend mutable to member functions


Author: "Carl Nygard" <cjnygard@fast.net>
Date: Tue, 26 Feb 2002 20:46:59 GMT
Raw View
//
// This proposal is motivated by cache objects and the mutable storage
// specifier.  It would be useful for overall static type checking to
// extend the mutable keyword to apply to member functions as well as
// member data.  This would restrict access to mutable data, allowing
// only mutable functions to write to the mutable data members of
// const objects.  The rules would be as follows:
//
// non-const member function  - r/w access to all member data
// mutable member function - r/w access to mutable data, r-o to non-mutabl
// const member function - read only to all member data
//
// The Motivating example stems from Stroustrop TC++PL 10.2.7.2
// section on Mutable, which discusses the uses of mutable,
// specifically when dealing with internal cache objects.
//
// There are two recommend (by Stroustrop) ways to deal with
// changeable cache data.  One way is to make the cache object
// mutable, the other is to use a reference as indirection to hide the
// const-ness of the cache object inside const member functions.
//
// I've included and expanded the code from 10.2.7.2 to illustrate a
// proposal for an additional access specifier for member functions
// that makes access control for mutable member data more explicit.
//

#include <string>

struct Cache {
    Cache() : valid(false), rep("") {}
    bool valid;
    string rep;
};

class Date {
#if MUTABLE// Optional impl #1
    mutable Cache cache;
#else // Optional impl #2
    Cache c;
    Cache& cache;
#endif

    time_t date;
    void compute_cache_value() const;
public:
    Date() : cache(c) {}
    string string_rep() const;
    time_t date_diff(const Date& date) const;
};

void Date::compute_cache_value() const
{
    // ... compute Cache::rep ...
    cache.rep = "today";
    cache.valid = true;
}

string Date::string_rep() const
{
    if(!cache.valid){
        compute_cache_value();
    }
    return cache.rep;
}

time_t Date::date_diff(const Date& date) const
{
    time_t diff;
    if(cache.valid = true) {        // error, should be ==
        // ... do something
    }
    return diff;
}


// Note the intentional error in the date_diff() function, which
// instead of using a comparison == Cache::valid is assigning the
// value.  If the object's cache has not been properly initialized,
// this will result in wrong behaviour.  Neither implementations of
// the Cache to allow mutable behaviour will allow a compiler to catch
// this error, and while some compilers (DEC cxx for one) will output
// a warning, errors of this type are notoriously difficult to find.
//
// Use of the mutable keyword for member functions would change the
// Date class like so:

#if 0  // So the example compiles

class Date {
    mutable Cache cache;
    time_t date;
    void compute_cache_value() mutable;
public:
    Date() {}
    string string_rep() const;
    time_t date_diff(const Date& date) const;
};

#endif

// Making the compute_cache_value() function mutable would allow it
// access to the Cache data member, while preventing the date_diff()
// function from compiling

int main(int argc, char** argv) {}  // so this code compiles

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: Wed, 27 Feb 2002 16:57:09 GMT
Raw View
"Carl Nygard" <cjnygard@fast.net> writes:

>// This proposal is motivated by cache objects and the mutable storage
>// specifier.  It would be useful for overall static type checking to
>// extend the mutable keyword to apply to member functions as well as
>// member data.  This would restrict access to mutable data, allowing
>// only mutable functions to write to the mutable data members of
>// const objects.  The rules would be as follows:
>//
>// non-const member function  - r/w access to all member data
>// mutable member function - r/w access to mutable data, r-o to non-mutabl
>// const member function - read only to all member data

What about
 - access to member data (of a const object) from non-member functions?
 - calling a mutable member function from a const member function?
 - calling a mutable member function (of a const object)
   from a non-member function?

This proposal is IMHO a bad idea.  Whether or not a member function
modifies mutable data is an implementation detail, and therefore should
not be part of the type of that function.

This proposal would complicate the language, and make the notion of
`mutable' more confusing than is necessary.  The amount of additional
checking that it would achieve is not worth this increase in complexity
and loss of coherence.  And furthermore it would break backwards
compatibility (since currently const member functions get r/w access to
mutable data).

>time_t Date::date_diff(const Date& date) const
>{
>    time_t diff;
>    if(cache.valid = true) {        // error, should be ==

Errors like this are likely to arise far more often for ordinary
(non-const, non-mutable) data members in ordinary member functions,
than for mutable data members in const member functions.
So your proposal would only help catch a very very small number of errors.
And errors like this can be caught by existing compiler warnings.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
The University of Melbourne         |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- the last words of T. S. Garp.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Carl Nygard" <cjnygard@fast.net>
Date: Wed, 27 Feb 2002 19:15:38 GMT
Raw View
In article <a5igng$3v9$1@mulga.cs.mu.OZ.AU>, fjh@cs.mu.oz.au  wrote:

> "Carl Nygard" <cjnygard@fast.net> writes:
>
>>// This proposal is motivated by cache objects and the mutable storage
>>// specifier.  It would be useful for overall static type checking to
>>// extend the mutable keyword to apply to member functions as well as
>>// member data.  This would restrict access to mutable data, allowing
>>// only mutable functions to write to the mutable data members of
>>// const objects.  The rules would be as follows:
>>//
>>// non-const member function  - r/w access to all member data
>>// mutable member function - r/w access to mutable data, r-o to
>>non-mutabl
>>// const member function - read only to all member data
>
> What about
>  - access to member data (of a const object) from non-member functions?

Existing C++ access rules would apply.

>  - calling a mutable member function from a const member function?

I now realize I've been thinking about the problem from two different
directions at the same time.  On one hand, mutable would be a new access
specifier, in between const and non-const, such that non-const could call
mutable or const member functions, mutable could call const member
functions, and const can call const member functions.  However, this would
also involve mutable object types, mutable_cast<>, etc.  Ugh.

The other way I've been thinking about it is much simpler.  A mutable
member function is the same as a const member function, but it can modify
mutable data members.  Simple.  So a const member function can call a
mutable member function, non-member functions can call mutable member
functions on a const object.

I think this simpler way is what I was first thinking about, basically a
way to provide access control over mutable data members, such that we get
greater compile-time validity checking, without a lot of language
overhead.

>  - calling a mutable member function (of a const object)
>    from a non-member function?

Permissible, rule #2.

>
> This proposal is IMHO a bad idea.  Whether or not a member function
> modifies mutable data is an implementation detail, and therefore should
> not be part of the type of that function.

If you remove 'mutable' from the above sentence, you could be arguing
against const member functions.  We all know const is good;)

Seriously, this is the type of implementation detail that gets screwed
up easily.  Any help from the compiler would be a good thing.

>
> This proposal would complicate the language, and make the notion of
> `mutable' more confusing than is necessary.  The amount of additional
> checking that it would achieve is not worth this increase in complexity
> and loss of coherence.  And furthermore it would break backwards
> compatibility (since currently const member functions get r/w access to
> mutable data).

I agree that there are ways to make it more complicated, but I think it
can also be quite simple.  However, I don't think it will add that much
additional compiler complexity since we are just checking for mutable
access internally to the member function.  To the outside world, mutable
member function == const member function.

And yes, it would break backward compatibility, and I'm not sure what to
say about that, other than I'm sure a compile flag like
--const_equals_mutable would help.


>
>>time_t Date::date_diff(const Date& date) const
>>{
>>    time_t diff; if(cache.valid = true) {        // error, should be ==
>
> Errors like this are likely to arise far more often for ordinary
> (non-const, non-mutable) data members in ordinary member functions,
> than for mutable data members in const member functions. So your
> proposal would only help catch a very very small number of errors. And
> errors like this can be caught by existing compiler warnings.
>

Only if such errors were added to existing compilers.  I got no warnings,
with the exception of DEC cxx warning about assignment inside an if(),
which was emitted for a totally different reason.  gcc and aCC compiled
clean.

Regards,
Carl

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]