View mode: basic / threaded / horizontal-split · Log in · Help
September 11, 2007
Re: Transitive const sucks
On 9/11/07, Sean Kelly <sean@f4.ca> wrote:
>
> My classic example for the need of "mutable" is a mutex used to
> synchronize access to class data.  The mutex must be modified even for
> read operations.


Again, if we let D's "private" attribute also imply C++'s "mutable", then
that problem goes away.
September 11, 2007
Re: Transitive const sucks
"Janice Caron" wrote
> What all of these use-cases have in common is the fact that the state is 
> private
>
> Suppose that all class and struct members which were declared private, 
> were always mutable,
> even if the class instance is const.

I sort of agree with you, but what about instances where you want derived 
classes to be able to access the cache?

I think having a keyword for mutable is necessary, but what may make sense 
is to enforce that only non-public members are allowed to be mutable.

What is the argument against mutable again?

-Steve
September 11, 2007
Re: Transitive const sucks
On 9/11/07, Steven Schveighoffer <schveiguy@yahoo.com> wrote:
> "Janice Caron" wrote
> > What all of these use-cases have in common is the fact that the state is
> > private
> >
> > Suppose that all class and struct members which were declared private,
> > were always mutable,
> > even if the class instance is const.
>
> I sort of agree with you,

I believe I can make the case for my argument stronger. In general,
when I expose a class's interface, the understood contract is:

class C
{
    public:
        /* stuff I want you to know about */

    private:
        /* None of your gorram business. It's PRIVATE.
           You shouldn't care know or care what's in here */
}

To a caller of the code, it should not matter what member functions of
C do to its private members, so long as the public interface does what
you expect.

Here's another use case. Suppose I start off with a simple class like:

class C
{
    void f() { /* do something */ }
}

const C c;
c.f();

But later, as I'm debugging the code, I realise it's not doing quite
what I want it to do, and I need to put some diagnostic code in to
help me with debugging. So I change it to:

class C
{
    void f() { debug ++count; /* do something */ }
    debug private int count;
}

const C c;
c.f();

Whoops! Now it won't compile in debug mode (but it will still compile
in release mode). Again, it's because /private/ state is conflicting
with the constness.



> but what about instances where you want derived
> classes to be able to access the cache?

I can't think of a use-case for that.

Would it not suffice for the base-class to expose protected functions
to provide read-only access to the cache?



> I think having a keyword for mutable is necessary

I believe this thread has shown that there is a need for the
/functionality/ that the keyword provides, but I'm not completely
convinced that we need the keyword itself. If we allow private data to
be implicitly mutable then we don't need the keyword.


> but what may make sense
> is to enforce that only non-public members are allowed to be mutable.

My idea would make that enforcement unnecessary


> What is the argument against mutable again?

In C++, you can do this:

class C
{
public:
    mutable int x;
    C() { x = 0; }
    void f() const { x = 5; }
}

main()
{
    const C c;
    printf("%d\n", c.x); /* prints 0; */
    c.f();
    printf("%d\n", c.x); /* prints 5; */
}

This is clearly nonsense.

That would be disallowed in my scheme. (...at least, if main() was in
a different file from the definition of C).
September 11, 2007
Re: Transitive const sucks
"Janice Caron" wrote
> On 9/11/07, Steven Schveighoffer <schveiguy@yahoo.com> wrote:
>> "Janice Caron" wrote
>> > What all of these use-cases have in common is the fact that the state 
>> > is
>> > private
>> >
>> > Suppose that all class and struct members which were declared private,
>> > were always mutable,
>> > even if the class instance is const.
>>
>> I sort of agree with you,
>
> I believe I can make the case for my argument stronger. In general,
> when I expose a class's interface, the understood contract is:
>
> class C
> {
>     public:
>         /* stuff I want you to know about */
>
>     private:
>         /* None of your gorram business. It's PRIVATE.
>            You shouldn't care know or care what's in here */
> }

Yeah, I understand your original point.  I'm not disputing that, which is 
why I "sort of" agree with you.  My point that protected should be able to 
be mutable as well as private was the point I was trying to make.

>> but what about instances where you want derived
>> classes to be able to access the cache?
>
> I can't think of a use-case for that.

The one that comes to mind is if you wanted to slightly modify the way a 
cache was used.  The two options are: make the cache protected, and allow 
derived classes to use it (in which case mutable is required), or 
re-implement the cache in the slightly modified way in the derived class, in 
which case you are carrying around 2 caches for no reason.

> Would it not suffice for the base-class to expose protected functions
> to provide read-only access to the cache?

Well, yeah, you could do it that way, but you would have to know before-hand 
how your cache was going to be accessed/used by the derived classes, 
therefore restricting the creativity of the author of the derived class.

>> What is the argument against mutable again?
>
> In C++, you can do this:
>
> class C
> {
> public:
>     mutable int x;
>     C() { x = 0; }
>     void f() const { x = 5; }
> }
>
> main()
> {
>     const C c;
>     printf("%d\n", c.x); /* prints 0; */
>     c.f();
>     printf("%d\n", c.x); /* prints 5; */
> }
>
> This is clearly nonsense.
>
// tango style
class NonsenseInD
{
 private int _x = 0;
 int x() const { return _x;}
 void f() const { x = 5;}
}

// could be in another file
int main(char[][] args)
{
 const NonsenseInD c = new NonsenseInD;
 Stdout(c.x).newline; // prints 0;
 c.f();
 Stdout(c.x).newline; // prints 5;
}

Even with this example, I still don't see why mutable is such a horrible 
thing...  To me it makes sense to have pieces of a class that can change, 
even when the class is const.  You have given several good examples (files, 
net connections, etc), but I think your idea of enforcing public data being 
const is probably not feasible.

-Steve
September 11, 2007
Re: Transitive const sucks
On 9/11/07, Steven Schveighoffer <schveiguy@yahoo.com> wrote:

> // tango style
> class NonsenseInD
> {
>   private int _x = 0;
>   int x() const { return _x;}
>   void f() const { x = 5;}
> }
>
> // could be in another file
> int main(char[][] args)
> {
>   const NonsenseInD c = new NonsenseInD;
>   Stdout(c.x).newline; // prints 0;

No it won't, because it won't compile, because x is private.

(It will compile if main is in the same file as class NonsenseInD, but
I can live with that).
September 11, 2007
Re: Transitive const sucks
> No it won't, because it won't compile, because x is private.

Sorry - accept my apologies - I misread your code.
September 11, 2007
Re: Transitive const sucks
Steven Schveighoffer wrote:
> "Janice Caron" wrote
>> On 9/11/07, Steven Schveighoffer <schveiguy@yahoo.com> wrote:
>>> but what about instances where you want derived
>>> classes to be able to access the cache?
>> I can't think of a use-case for that.
> 
> The one that comes to mind is if you wanted to slightly modify the way a 
> cache was used.  The two options are: make the cache protected, and allow 
> derived classes to use it (in which case mutable is required), or 
> re-implement the cache in the slightly modified way in the derived class, in 
> which case you are carrying around 2 caches for no reason.

Provide a property to access the cache. It'll likely be inlined, so no 
performance hit.
September 11, 2007
Re: Transitive const sucks
Janice Caron wrote:
> On 9/11/07, Steven Schveighoffer <schveiguy@yahoo.com> wrote:
>> What is the argument against mutable again?
> 
> In C++, you can do this:
> 
>  class C
>  {
>  public:
>      mutable int x;
>      C() { x = 0; }
>      void f() const { x = 5; }
>  }
> 
>  main()
>  {
>      const C c;
>      printf("%d\n", c.x); /* prints 0; */
>      c.f();
>      printf("%d\n", c.x); /* prints 5; */
>  }
> 
> This is clearly nonsense.
> 
> That would be disallowed in my scheme. (...at least, if main() was in
> a different file from the definition of C).

And why is this nonsense?? Because x is public? I don't see the problem 
here.

-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
September 11, 2007
Re: Transitive const sucks
Sean Kelly wrote:
> read operations.  But for better or worse, D const has a different aim. 
>  The goal is largely to produce a system which allows for compiler 
> optimization rather than to enforce some sort of logical restrictions on 
> behavior.  I suspect this means that D apps won't look very much like 
> C++ apps in terms of how const is used, and the overall utility for the 
> average programmer may well be somewhat small.
> 
> 
> Sean

I'm don't think that's entirely true. 'invariant' the keyword is indeed 
made to allow several compiler and program optimizations, but 'const' 
the keyword is really for enforcing program contracts and restrictions, 
thus improving safety. I don't even think 'const' the keyword has any 
use whatsoever for optimization.


-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
September 11, 2007
Re: Transitive const sucks
> And why is this nonsense?? Because x is public? I don't see the problem
> here.

What's the use-case for mutable non-private members?

I would say that it's nonsense if there's no need for them.

"Nonsense" may be the wrong word. "Should not be part of D" is more
what I really mean.
1 2 3 4 5 6
Top | Discussion index | About this forum | D home