May 02, 2012
> But that's definitely not the case in C#.

(which, I should clarify, was what implicitly came to my mind as an example of immutable strings) 

May 02, 2012
On 2012-05-02 18:01, Mehrdad wrote:
>> When you're making the object 'const', you're not making the
>> assumption that no one who derives from this class need mutable state.
>> What you're doing is asserting that bits belonging to this object
>> needs to be 'const' to preserve sequential consistency across threads
>> or for other reasons.
>
> Bits belonging to *this* object? I thought const was transitive...
>
>> If the derived class casts away const, it breaks that contract.
>
> So you're saying the same thing: Derived classes CANNOT have mutable
> state...

No:

interface Foo
{
    void foo () const;
}

class Bar : Foo
{
    int x;

    void foo () const {}

    void bar ()
    {
        x++;
    }
}

void main()
{
    auto bar = new Bar;
    bar.bar();
    writeln(bar.x);
}

-- 
/Jacob Carlborg
May 02, 2012
Er, I guess I didn't say what I actually meant to say, my bad. x_x

What I meant that you're assuming that derived classes won't need mutable state in an const method that they overrode. 

May 02, 2012
On Wednesday, 2 May 2012 at 15:35:15 UTC, Mehrdad wrote:
> I guess this answers my question then: const/immutable are useful for multithreading.

Indeed, const/immutable makes multithreading much better. It
provides restrictions which make it much easier to think about
problems. If I pass a const reference into a function, I can be
guaranteed it won't be changed by that function.

> So it means, essentially, they're pretty useless for Objects, but only useful for structs.
> Why? Objects have **behavior** (not just data) ...

Structs in D have behavior as well. In fact, I've found most
things I might be forced to use objects/classes in most other
languages can be easily done with D's structs and all of the
behavior and state is encapsulated nicely. Combine that with
templates and you've got some ridiculous power and efficiency.

> Sure, the method writer can call the method 'const', but he really has no idea whether someone will override it down the road and get struck by lightning because of that.

If the method writer has the method be const, then he's said that
the contract of that method is that it doesn't change the
object's state. This is no different than having a method that
takes a string and complaining that the method writer has no idea
whether someone will want to override it later and want the
method to take an int.

You can overload the method to take an int. And you can overload
the method later down the line so that you have an implementation
which does mutate state and isn't const. Although, you certainly
need to have a version which doesn't mutate state available
still. But that's just part of the contract.

If you're writing a method and you've decided "I want whoever
uses this method to not cause any mutation of state when they
call this method" (maybe so there's a guarantee of consistency in
execution speed between calls or something), then you mark it
const. Otherwise, it's not really a const method.

> Because of that, I think we disallow direct instantiation of const() or immutable() Objects altogether, because they're pretty useless.

Why? There's no reason to throw the baby out with the bath water.
There's plenty of need for inheritance for immutable/const
representation of data. Just because we can't use it for objects
whose whole life is caching (which is a clear subset of OOP usage)
doesn't mean it's useless.

> Huh? Not if they're instance variables.
> It's kind of silly to lock against something so you can modify instance variables.

Depends. If you're just accessing the instance method directly
(and it's an atomic operation), you can get away with not locking.

However, If you have a C++ const object and you call a getter
method on it in a context where someone else may also be calling
a getter method on it, you must lock it. By your own admission,
you can't depend on implementation of the object. Ergo, the
getter methods may be mutating state (you can't assume it's not),
and you can't tell whether or not they are because const in C++
doesn't say whether it will mutate state. Of course, if you don't
depend on the correctness of the method you're free to not lock...

In D, if I'm sure these const objects aren't being modified
elsewhere, I can absolutely get away with not locking when I call
getter methods. If it's an immutable object, it doesn't even
cross my mind whether I need to lock it or not. You don't have
that kind of peace of mind in C++.


> I don't think I ever violated C++'s 'const'... (?)

Well, seeing as C++ const apparently has no meaning ... it's
rather hard to "violate" it, per say. Honestly, the time my
professors taught me about C++'s const, they said it was for
methods that don't modify state. Evidently that wasn't the case,
but I never got into the mindset that const didn't mean something
that doesn't modify state... so it's rather hard for me to think
of a reason to use const for this. Const to me has always meant
"don't mutate state." If you just want a view of the object where
you only use getters, that's really what D's interfaces are for.

> More like, a **CHECKED** comment.
> Big difference.

Not exactly. It's not "checked" because const objects can be
changed by anyone at anytime easily and it's common and the
compiler doesn't care. It doesn't mean anything.

Again, what I think you actually want is an interface of the
getters, not const. There's no sense in having both do the same
thing when we can actually use const to mean an object that you
won't mutate.

=-=-=-=

In any case, would the Student-getter style interface method work
for this use case or not?

interface IStudentRO {
    string getName();
    string getAddress();
    real getGPA();
    ...
}

class Student : IStudentRO {
    IConnection conn;
    string name;
    ...
    string getName() {
       if(!name)
          name = conn.get("name");
       return name;
    }
    ...
    void setName(string newName) {
       name = newName;
       conn.set("name", newName);
    }
    ...
}

void process1(IStudentRO student); // Compile-time checking ...
can only use getters.
May 02, 2012
On 05/02/2012 08:58 PM, Mehrdad wrote:
> mutable state in an const method

=O

May 02, 2012
Okay thanks for the replies, that clears up a bunch of things for me.

Regarding the last part:

Yes, it 'works'. The only trouble is that you can never set the interface methods to be 'const', because any sort of indirection can screw you over later. This is why const is less useful than it could be. 

May 02, 2012
"Timon Gehr"  wrote in message news:jns5du$64q$1@digitalmars.com... On 05/02/2012 08:58 PM, Mehrdad wrote:
> > mutable state in an const method
> =O


a*
May 02, 2012
On Wednesday, 2 May 2012 at 20:30:10 UTC, Mehrdad wrote:
> Okay thanks for the replies, that clears up a bunch of things for me.

No problem, I'm glad it's helping.

> Regarding the last part:
>
> Yes, it 'works'. The only trouble is that you can never set the interface methods to be 'const', because any sort of indirection can screw you over later. This is why const is less useful than it could be.

You can set interface methods to be const, but you have to
understand that you're saying that method can't mutate state.
There's also nothing stopping you from specifying that both const
and non-const methods are available, but it would increase the
workload of people down the line especially if the const and
non-const version differ significantly.

I think D's const is as useful as it needs/can be. That said, I
can understand why you might feel that way until you start using
const/immutable correctly. Once you see how it improves your
conceptual model of approaching algorithms, I won't be surprised
if you end up as annoyed with C++'s const as I am. It's kind of why I pointed out the whole thing where you should lock your object even when you're just calling getters on a const object. It's actually deceptively incorrect to not do that in C++.
May 02, 2012
On 2012-05-02 20:58, Mehrdad wrote:
> Er, I guess I didn't say what I actually meant to say, my bad. x_x
>
> What I meant that you're assuming that derived classes won't need
> mutable state in an const method that they overrode.

Yes, that would be the assumption. It's not possible without subverting the type system. It's like saying "I'm overriding this method but I want it to return an int instead of a string". It's part of the interface.

-- 
/Jacob Carlborg
May 02, 2012
On Wednesday, May 02, 2012 13:30:11 Mehrdad wrote:
> Okay thanks for the replies, that clears up a bunch of things for me.
> 
> Regarding the last part:
> 
> Yes, it 'works'. The only trouble is that you can never set the interface methods to be 'const', because any sort of indirection can screw you over later. This is why const is less useful than it could be.

You _can_ make the interface methods const if you're willing to deal with that restriction in everything that implements it. Sometimes that's reasonable. Sometimes it's not. The simple truth of the matter is that you can't just const in D as much as you would in C++, simply because it's more restrictive. It's more powerful thanks to its greater guarantees, but that comes at a cost. So, programmers are going to have to learn when using const in D makes sense and when it doesn't, even if they're experts at in C++. And a lot of it depends on what you're doing (e.g. I pretty much never lazy load anything, so const would never cause me problems due to disallowing lazy loading, but for someone who needs lazy loading for performance, const make be unacceptable in many cases).

- Jonathan M Davis