Transitive const sucks

Walter Bright newshound1 at digitalmars.com
Wed Sep 12 12:19:28 PDT 2007


BTW, Janice, I appreciate your thoughts on this. You're obviously an 
experienced programmer.

Janice Caron wrote:
> But you could guarantee that /non-private/ data will not change. And 
> since non-private data is never seen outside the file in which it is 
> declared, I don't understand why this is a problem.

Because multithreaded programming doesn't start working if the interface 
hides the changing variables. If it did, parallel programming would be 
easy. Logical constness is *still* changing state, and since it is, all 
the boogeymen of synchronization, race conditions, deadlocks, etc., are 
all there.

Logical constness hides the state change from the awareness of the 
programmer, but it's still changing state.

>     and even worse, I can't even tell this is happening. "I" here meaning
>     the compiler, and our hapless code auditor.
> Providing you restrict "logical constness" to private variables, is that 
> really true? Inside the module, the compiler knows everything. Outside 
> the module, the private variables are irrelevant anyway as they can 
> never be accessed in any way.

Being in a module doesn't prevent another thread from using the module's 
interface and thereby changing the state.


> Functional programming isn't possible anyway unless the function can 
> also guarantee that it won't modify /global/ variables, and I see no way 
> of specifying that in the prototype.

The upcoming 'pure' storage class for a function will resolve that.


> Even if you could, it's more complicated than that. A function might 
> modify global variables and yet still be threadsafe - providing it uses 
> mutexes to ensure it has exclusive access to the shared variables. A 
> good example of this is writef(). The writef() function writes to 
> standard output, and so /must/ modify some global state - but it's 
> thread-safe because file access is all mutex locked.

Yes, but that requires programmer discipline, which is unreliable and 
scales poorly. Very few programmers are able to successfully write such 
code. With FP programming, most programmers will be able to.


> Moreover, multithreaded programming might /require/ you to lock a mutex, 
> do something, then unlock said mutex. The mutex itself needs to be 
> modifiable - that is, "logically const".
> 
> More thought needs to be put into that one.

It has come up before. The answer is to not declare logically const 
things as being const, because they aren't const. Logical constness 
belongs as a comment because it is not compiler checkable.



>     3) having a tightly specified interface
> 
> Interfaces are my concern. If an Interface specifies that a function be 
> const (in the sense of non modifying member variables), then it would 
> make a lot of sense that classes which implement that interface be 
> allowed to assume the interface means "logical constness", for the 
> reasons of all the use-cases given so far.

I'll reiterate that const-that-isn't-checkably-constant has no value 
beyond being a comment, so it might as well just be a comment.


>     It goes back to painting a stripe across your hips and calling it a
>     seatbelt.
> 
>     Given this, it isn't any surprise that C++ is disastrously difficult to
>     write functional & multithreaded programs in, and C++ mutability is one
>     of the reasons why. In C++, you can write const this and const that and
>     it doesn't mean jack squat. Many experienced C++ programmers will tell
>     you that const is little more than a documentation aid.
> 
> 
> I /am/ an experienced C++ programmer,

I can tell <g>. The logical constness pattern comes from C++.

> Outside the module, that's all you need to 
> know. Inside the module, the compiler knows all anyway.

The D compiler does not necessarily know all there is to know about a type:
1) If you're writing generic code, with things like const(T), you don't 
know what T is. Therefore, as a programmer, you will not be able to 
write generically pure code.
2) D allows for so-called abstract types, where the compiler does not 
know the internals of the type. This is used in the Phobos to hide 
implementation details. Therefore, the compiler cannot tell if a const T 
has mutability or not.


> And I'd end up with something that was much nastier than the very thing 
> you are trying to avoid.

The error I see in the example is declaring rand() to be const. Why do 
that if it IS NOT constant? You can already hide members the user 
shouldn't be modifying with 'private', why layer 'const' over that, too?



More information about the Digitalmars-d mailing list