Why D const is annoying

Chris Cain clcain at uncg.edu
Wed May 2 04:41:40 PDT 2012


On Wednesday, 2 May 2012 at 06:10:04 UTC, Mehrdad wrote:
> I don't think you answered my question.
>
> What I said (or meant to ask) was this:
> - OK, FINE, let's say I don't know what D's const() means, 
> then. Maybe it isn't suitable for what I need. I just want to 
> know:
>  _How do you specify that the function process1() won't modify 
> its 'student' parameter_?

If you want just to specify that (and not ask the compiler to 
check for you), documentation will do.

>
> Your response was this:
> - "Does const(Student) mean that it shouldn't write to the 
> server?"
>
> To which my answer is:
> - I don't know, you tell me. (?) _Should_ I use 'const' to 
> specify this? Or should I use something else?

I can't tell you what you want. You have to tell me. But no, you 
shouldn't use const to specify this. const means you're object 
won't be changed by you. Here's a decision tree for if you can 
use const and immutable

Will the object (including all of its fields) ever change?
no -> immutable (END)
yes ->
Will the object (including all of its fields) be changed by you?
no -> const (END)
yes -> No qualifier

That's _any_ kind of modification of state. If you change state, 
you can't use immutable/const (nor would you really want to).

> The problem with your answer is that it implies D DOESN'T 
> SUPPORT O.O.P. with const!!!
>
> If D supported OOP, then why the heck would process1() know (or 
> _care_) how Student works internally?
> Why (or how) should it know (or care) that Student uses a 
> database connection?

When you say "const(Student)" you're saying that whatever Student 
does, you want to know whatever you do won't change its internal 
state.

I'm not sure you're using OOP properly. If you want to use OOP to 
solve the problem, my suggestion is closer to OOP than using 
const. If you don't want to talk about database connections and 
everything (i.e., you don't want to use D's outrageously nice 
templates), you can just have it be an interface instead. In fact 
an interface would probably be more appropriate.

interface ROStudent {
    getName();
    getAddress();
    ...
}

process1(ROStudent student);

Effectively, though, it's the same sort of thing.

D's const/immutable require a different way of thinking of it. 
What are they useful for? Consider a multithreaded program where 
some threads depend on information that others have. They need 
the information but they won't change state (which makes it much 
safer/faster to work with because locking isn't as necessary ... 
with immutable locking is actually silly). That's what 
const/immutable is for.

In C++, you'd be foolish to not have locks set up even for const 
variables because they can change at any time for any reason. 
It's hardly a guarantee and it's so common to violate (look at 
yourself, for instance) that it means _nothing_. I liked how it 
was described as a glorified comment, because that's precisely 
how I think of it.

> Wasn't that information an implementation detail?
>
>
> All process1() needs to know is the *PUBLIC INTERFACE* of 
> Student.
> And all it cares to say is: "According to the public interface 
> of Student, none of the methods I will use will modify the 
> object."
> process1() has NO IDEA what goes on internally! It has NO IDEA 
> that Student uses a database connection. Maybe it's a network 
> connnection instead. Or maybe it's being unit-tested, and it's 
> actually a dummy object, with no relation to the outside world. 
> Or maybe it's a wrapper/proxy for another object.
>
> The point is: _why should the code for process1() depend on 
> this_?!

If that's what you want, then that's precisely what D does. 
"According to the public interface of Student, none of the 
methods I will use will modify the object." As opposed to C++'s 
method of "According to the public interface of student, these 
methods have comments that say that they say they won't change 
the object, but I can't tell if it does or not."

Again, using an interface ROStudent/StudentReader/etc is really 
your "OOP solution".

>
>
>
>
> So, I'll ask my question again:
>
> How should process1() tell the outside world that it will not 
> be asking its parameter to manipulate itself, WITHOUT breaking 
> the abstraction barrier and 'peeking' into the private world of 
> Student?

I'll respond again: It depends on what you want. If you won't be 
changing the object, then const/immutable does that. If you will 
be changing the object, but you want guarantees that it won't 
write to some external source/data structure, you'll have to come 
up with the more precise way you want to define that. I gave you 
two potential approaches.


----

Really though, the C++ way is a complete and total minefield in 
this regard anyway. Consider Student defined like so:

Student {
name, id, address, phone_number;
connection;
getName() const {
     if(!name) {
         // cast away const
         thisnonconst.name = connection.get("name");
     }
     return name;
}
writeName() {
     connection.set("name", name);
}
}

Now this follows one particular understanding of const (the one I 
think you're getting at). However, imagine another person comes 
along and sees that "writeName" doesn't write to Student's state. 
Helpfully, he adds const to the end of writeName and breaks your 
type system. In fact, it's actually _easier_ to violate "that 
kind of const" than it is to use it, because your "getName" 
method has to do fancy casting away of const.

In fact, D's way, if you specify that Student can only use a 
ReadOnlyConnection (or if you use ROStudent/StudentReader 
interface), then the compiler will guarantee that it has a 
ReadOnlyConnection. If ReadOnlyConnection doesn't write to the 
database, then that Student is _guaranteed_ to not write to the 
database.

If you want the compiler to check that, the D offers the ability 
to. C++, on the other hand (using const), can barely suggest that 
possibility, since it's so easy to violate.




More information about the Digitalmars-d mailing list