May 02, 2012
On Tuesday, May 01, 2012 23:14:06 Mehrdad wrote:
> > In C++, the compiler can't use it to provide any real guarantees, because the programmer is free to violate const at any time via mutable or casting away const.
> 
> Maybe I'm being stupid, but how is the case any different in D?

D's type system assumes that const cannot be altered. As such, the compiler is free to optimize or alter its code generation based on that fact and any code which _does_ alter a variable after casting away const is breaking the type system and risking bugs. As far as the compiler is concerned, you _cannot_ alter a const variable through that variable (though another one might - unlike immutable - meaning that there are times when the compiler can't know that a const variable hasn't been mutated; it often can, however, particularly within a single function).

C++ specifically allows for const variables to be altered - either via mutable or casting away const. It _guarantees_ that it work to do so. And since it considers it completely legal to alter a const variable by either of those means, it _cannot_ assume that a const variable hasn't been altered except in very restricted circumstances. So, in general, the _only_ guarantee that C++'s const gives you is that you a const variable will not be altered save by casting away const or by one of its member variables being mutable.

So, it all comes down to what the compiler is free to assume and therefore guarantee. With D's type system, it's free to assume that you can never alter a const variable, so it guarantees that and any attempt to subvert that breaks the type system and whatever guarantees it gives you, risking bugs. With C++'s type system, it assumes that const _can_ be mutated via casting or mutable and guarantees that that will work, whereas it then _cannot_ assume that a const variable doesn't get mutated.

- Jonathan M Davis
May 02, 2012
On Tuesday, May 01, 2012 23:10:04 Mehrdad wrote:
> "Chris Cain"  wrote in message news:nqgwunggifrgmwwhkcql@forum.dlang.org...
> 
> > What about the object do you want const? How should this object normally change things? It looks like the way you've coded it, your connection will get information off of a server.
> 
> 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_?

What you're thinking about here is logical const. You want a way to indicate that an object is not logically altered by the function that you're passing it to. With logical const, the inner state of the object _can_ change so long as the state of the object as seen from the outside is constante.

However, D's const is _physical_ const. It guarantees that the object isn't altered _at all_. And that _is_ part of the interface, because no non-const function can be called on a const object, and every const function statically guarantees that it doesn't mutate the object that it's on.

There is _no_ way in D to indicate that an object won't be altered by a function save for guaranteeing that it won't be altered _at all_ by using const. There is no way to indicate that it won't be altered logically save for comments.

And in reality, having the compiler verify that an object's logical state doesn't change even when some of its internal state does is _very_ difficult (if not impossible) to statically verify. As such, the compiler can make no such guarantees. Not even C++ does that. Arguably, C++'s const is a glorified comment. Walter certainly sees it that way and doesn't think that there is _any_ value to C++'s const as a result. What it _does_ guarantee is that you won't accidentally alter the object (since you have to cast away const to alter it, or some of its member variables are going to have to be mutable), so I'd argue that it's still very useful. But it does _not_ actually guarantee that the object won't get mutated by that function. It's effectively just a comment which the compiler partially verifies.

It would be _very_ cool to be able to have a compiler-checked, logical const, but it probably isn't realistically possible, except maybe in very restrictive circumstances.

- Jonathan M Davis
May 02, 2012
You said:
"In C++, the compiler can't use it to provide any real **guarantees**..."

Now you're telling me D doesn't guarantee it either.
And then go on telling me about how D uses const-ness to make assumptions and improve performance.

Isn't your answer orthogonal to your claim? o.O

Whether the compiler makes **GUARANTEES** about code is _irrelevant_ to whether or not the language uses 'const' to improve performance.

You could very well have a language which **enforces** const-ness (i.e. doesn't prevent casting it away), but which _doesn't_ use it to improve performance.
Or which does.


The dot product of your answer with my question was zero. :( 

May 02, 2012
In the world of OOP, when would "guarantee"ing (so to speak) 'physical' const-ness ever be handy?

Wouldn't "physical" const-ness be an implementation detail of the object, and therefore, impossible to determine by the user of the object? 

May 02, 2012
> ... i.e. doesn't prevent casting it away)


Typo, I meant "DOES prevent"
May 02, 2012
On Tuesday, May 01, 2012 23:44:30 Mehrdad wrote:
> You said:
> "In C++, the compiler can't use it to provide any real **guarantees**..."
> 
> Now you're telling me D doesn't guarantee it either.
> And then go on telling me about how D uses const-ness to make assumptions
> and improve performance.
> 
> Isn't your answer orthogonal to your claim? o.O
> 
> Whether the compiler makes **GUARANTEES** about code is _irrelevant_ to whether or not the language uses 'const' to improve performance.

No, what the compiler guarantees is _very_ relevant to using const for improving performance. The _only_ reason that the compiler can use const for any kind of optimizations is because it can guarantee that the variable won't change. If it can't guarantee that, then it _cannot_ use const for optimizations. How could it? What would there be to optimize? Optimizations with const are based on the fact that the variable didn't change, so if the compiler can't guarantee that, how could it make any optimizations based on that?

And yes, D's type system _does_ guarantee that a const object doesn't change specifically because casting away const and mutating an object is _undefined_. It goes outside of the type system. You can do it, because D is a systems language, but the compiler is free to make optimizations based on the assumption that you will never mutate a const variable. So, the compiler _can_ make the guarantee that const isn't mutated, and if you do, you _will_ have bugs - just like if you did something screwy like casting an object no void* nad then casting it to a completely different type afterwards could cause bugs. You've thrown away the type system at that point, and it's up to the programmer to maintain the compiler's guarantee in such situations, or you'll get bugs, because the compiler relies on that guarantee.

C++, on the other hand, _does_ define what happens when you cast away const and mutate a variable, so its type system has to assume that a const variable _can_ change and therefore can rarely use it for optimizations (i.e. only in cases where it can statically verify that you _didn't_ cast away const and that not mutable variables are involved - which is likely to be rather rather, since even just making a function call would defeat it, since C++ doesn't do cross-function optimizations like that).

The difference here is in what the compiler considers to be defined or not and therefore what assumptions it's permitted to make.

- Jonathan M Davis
May 02, 2012
Whoa, what?

So you're saying
    "X results in UB"
means
    "Compiler guarantees X"
?


By that philosophy, C and C++ are orders of magnitude better than D, given how many so-called "guarantees" they make about your code... 

May 02, 2012
On Tuesday, May 01, 2012 23:48:29 Mehrdad wrote:
> In the world of OOP, when would "guarantee"ing (so to speak) 'physical'
> const-ness ever be handy?
> 
> Wouldn't "physical" const-ness be an implementation detail of the object, and therefore, impossible to determine by the user of the object?

No, it's not an implementation detail. When you mark an object as being physically const, then you're guaranteeing that you will not alter it through that reference or pointer (and not at all, if it's a value type, because then there can't be another reference or pointer which mutates it). The type system guarantees this, because it disallows any const variable from being mutated.

When dealing with a const object, you can only call const functions on its interface. Whatever implementation there is for those interface methods would also have to be const to implement that interface. And the type system would then disallow any non-const functions being called within the implementations of those functions as well as disallowing the mutation of member variables. So, the type system guarantees that the object will not be mutated at all by any const function. And since const is part of the interface of the object, it is very much _not_ an implementation detail.

Physical constness is _required_ in order to have immutable ever be converted to const, because immutable objects can _never_ be mutated through _any_ reference or pointer. If D's const were not transitive as well as guarantee that any const reference cannot alter the object it points to, then you couldn't have immutable be convertible to const, because const would not protect it against mutation. So, C++'s const is impossible in D if immutable is going to be convertible to const.

It's _logical_ constness that is near-impossible to have the compiler verify, because it has no way of determining that the variables that you mark as mutable or from which you cast away const and mutate don't affect the logical state of the object. _You_ may know, but the compiler can't determine that.

- Jonathan M Davis
May 02, 2012
On Wednesday, May 02, 2012 00:10:33 Mehrdad wrote:
> Whoa, what?
> 
> So you're saying
>      "X results in UB"
> means
>      "Compiler guarantees X"
> ?
> 
> 
> By that philosophy, C and C++ are orders of magnitude better than D, given how many so-called "guarantees" they make about your code...

I don't follow.

The D compiler guarantees that as long as you don't cast away const, const will never be mutated. If you _do_ cast away const and then mutate the variable, you are doing something which is undefined. As it is undefined behavior, _anything_ could happen if you do it, and the compiler is free to assume that it will never happen. So, it effectively has a guarantee that a const variable will never be mutated (save by another, mutable reference to the same data). It then uses that guarantee for optimizations.

To make it 100% iron-clan, casting away const would have to be illegal, but that would be unacceptable in a systems language - particularly when you want to be able to call C functions which may not be properly annotated. So instead, the compiler assumes that its guarantee holds in the case where you cast away const, and is still able to use it for optimizations.

C++ _does_ define what happens when you cast away const and mutate a variable, so it guarantees that that behavior will be safe. In so doing however, it is then unable to assume that casting away const will not result in the variable being mutated and is therefore unable to use const for much in the way of optimizations.

- Jonathan M Davis


P.S. You can check out this stackoverflow question on the subject as well:

http://stackoverflow.com/questions/4219600/logical-const-in-d

May 02, 2012
On Wednesday, 2 May 2012 at 06:44:30 UTC, Mehrdad wrote:
> Whether the compiler makes **GUARANTEES** about code is _irrelevant_ to whether or not the language uses 'const' to improve performance.
>
> You could very well have a language which **enforces** const-ness (i.e. doesn't prevent casting it away), but which _doesn't_ use it to improve performance.
> Or which does.
>

Yes, pure functional languages do provide this kind of guarantee, by simply forbidding immutability at the cost of copying objects. I agree D's solution isn't "pure" as it must allow mutability, and I suspect it can't be, unless it starts copying objects all over the place. That means that when you use the immutable keyword, you *really* mean it and you *must* think that way. If you want to mutate your object, you have to copy it to another object. Thats how strings are designed. For me, your example doesn't prove that the tool is broken, it proves that you don't know how to use immutability. It's really another paradigm, which has its uses, in particular in concurrent programming.