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