www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - thoughts on immutability in D

reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
The initial submission got junked so I resubmitted:

http://www.reddit.com/r/programming/comments/knn5p/thoughts_on_immutability_in_d/


Andrei
Sep 21 2011
next sibling parent reply Peter Alexander <peter.alexander.au gmail.com> writes:
On 22/09/11 7:04 AM, Andrei Alexandrescu wrote:
 The initial submission got junked so I resubmitted:

 http://www.reddit.com/r/programming/comments/knn5p/thoughts_on_immutability_in_d/

 Andrei

Thanks for the reddit'ing. I launched up google analytics this morning and noticed a sudden spike. That could only mean one thing :-) Out of interest, does anyone have any criticism of my post, esp. if there's any technical inaccuracies (or just disagreement?)
Sep 22 2011
next sibling parent reply "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Thu, 22 Sep 2011 11:02:27 +0300, Peter Alexander
<peter.alexander.au gmail.com> wrote:

 Thanks for the reddit'ing. I launched up google analytics this morning  
 and noticed a sudden spike. That could only mean one thing :-)

I tried adding your blog to Planet D, but I can't figure out how to get an RSS feed of the D category on your blog. -- Best regards, Vladimir mailto:vladimir thecybershadow.net
Sep 22 2011
parent Peter Alexander <peter.alexander.au gmail.com> writes:
On 22/09/11 1:34 PM, Vladimir Panteleev wrote:
 On Thu, 22 Sep 2011 11:02:27 +0300, Peter Alexander
 <peter.alexander.au gmail.com> wrote:

 Thanks for the reddit'ing. I launched up google analytics this morning
 and noticed a sudden spike. That could only mean one thing :-)

I tried adding your blog to Planet D, but I can't figure out how to get an RSS feed of the D category on your blog.

I'll see what I can do about getting a D only RSS feed. In the meantime there is a all-inclusive RSS feed: http://poita.org/index.php?format=feed&type=rss
Sep 22 2011
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/22/11 3:02 AM, Peter Alexander wrote:
 On 22/09/11 7:04 AM, Andrei Alexandrescu wrote:
 The initial submission got junked so I resubmitted:

 http://www.reddit.com/r/programming/comments/knn5p/thoughts_on_immutability_in_d/


 Andrei

Thanks for the reddit'ing. I launched up google analytics this morning and noticed a sudden spike. That could only mean one thing :-) Out of interest, does anyone have any criticism of my post, esp. if there's any technical inaccuracies (or just disagreement?)

You could have specified that e.g. mutable state can be implemented safely with the help of a global hash table. Andrei
Sep 22 2011
next sibling parent reply Rainer Schuetze <r.sagitario gmx.de> writes:
On 9/22/2011 4:10 PM, Andrei Alexandrescu wrote:
 On 9/22/11 3:02 AM, Peter Alexander wrote:
 On 22/09/11 7:04 AM, Andrei Alexandrescu wrote:
 The initial submission got junked so I resubmitted:

 http://www.reddit.com/r/programming/comments/knn5p/thoughts_on_immutability_in_d/



 Andrei

Thanks for the reddit'ing. I launched up google analytics this morning and noticed a sudden spike. That could only mean one thing :-) Out of interest, does anyone have any criticism of my post, esp. if there's any technical inaccuracies (or just disagreement?)

You could have specified that e.g. mutable state can be implemented safely with the help of a global hash table. Andrei

If this is allowed by the compiler, doesn't that break all the guarantees transitive immutability tries to make? Aren't we back to "faith based programming" this way?
Sep 23 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/24/11 1:12 CDT, Rainer Schuetze wrote:
 On 9/22/2011 4:10 PM, Andrei Alexandrescu wrote:
 On 9/22/11 3:02 AM, Peter Alexander wrote:
 On 22/09/11 7:04 AM, Andrei Alexandrescu wrote:
 The initial submission got junked so I resubmitted:

 http://www.reddit.com/r/programming/comments/knn5p/thoughts_on_immutability_in_d/




 Andrei

Thanks for the reddit'ing. I launched up google analytics this morning and noticed a sudden spike. That could only mean one thing :-) Out of interest, does anyone have any criticism of my post, esp. if there's any technical inaccuracies (or just disagreement?)

You could have specified that e.g. mutable state can be implemented safely with the help of a global hash table. Andrei

If this is allowed by the compiler, doesn't that break all the guarantees transitive immutability tries to make? Aren't we back to "faith based programming" this way?

Not at all. Global mutable memory is what it is to everyone. Andrei
Sep 24 2011
parent reply Rainer Schuetze <r.sagitario gmx.de> writes:
On 9/24/2011 9:30 AM, Andrei Alexandrescu wrote:
 On 9/24/11 1:12 CDT, Rainer Schuetze wrote:
 On 9/22/2011 4:10 PM, Andrei Alexandrescu wrote:
 On 9/22/11 3:02 AM, Peter Alexander wrote:
 On 22/09/11 7:04 AM, Andrei Alexandrescu wrote:
 The initial submission got junked so I resubmitted:

 http://www.reddit.com/r/programming/comments/knn5p/thoughts_on_immutability_in_d/





 Andrei

Thanks for the reddit'ing. I launched up google analytics this morning and noticed a sudden spike. That could only mean one thing :-) Out of interest, does anyone have any criticism of my post, esp. if there's any technical inaccuracies (or just disagreement?)

You could have specified that e.g. mutable state can be implemented safely with the help of a global hash table. Andrei

If this is allowed by the compiler, doesn't that break all the guarantees transitive immutability tries to make? Aren't we back to "faith based programming" this way?

Not at all. Global mutable memory is what it is to everyone. Andrei

I'm probably missing something, but what are the guarantees given by the type system, if a property is implemented by a getter function: int globId; class C { property id() const { return ++globId; } } int main() { immutable(C) c = new immutable(C); return c.id; } Is c.id thread-safe? no! Is it constant? no! How does this help in multi-threaded applications that access c?
Sep 24 2011
next sibling parent reply Peter Alexander <peter.alexander.au gmail.com> writes:
On 24/09/11 9:46 AM, Rainer Schuetze wrote:
 On 9/24/2011 9:30 AM, Andrei Alexandrescu wrote:
 On 9/24/11 1:12 CDT, Rainer Schuetze wrote:
 On 9/22/2011 4:10 PM, Andrei Alexandrescu wrote:
 On 9/22/11 3:02 AM, Peter Alexander wrote:
 On 22/09/11 7:04 AM, Andrei Alexandrescu wrote:
 The initial submission got junked so I resubmitted:

 http://www.reddit.com/r/programming/comments/knn5p/thoughts_on_immutability_in_d/






 Andrei

Thanks for the reddit'ing. I launched up google analytics this morning and noticed a sudden spike. That could only mean one thing :-) Out of interest, does anyone have any criticism of my post, esp. if there's any technical inaccuracies (or just disagreement?)

You could have specified that e.g. mutable state can be implemented safely with the help of a global hash table. Andrei

If this is allowed by the compiler, doesn't that break all the guarantees transitive immutability tries to make? Aren't we back to "faith based programming" this way?

Not at all. Global mutable memory is what it is to everyone. Andrei

I'm probably missing something, but what are the guarantees given by the type system, if a property is implemented by a getter function: int globId; class C { property id() const { return ++globId; } } int main() { immutable(C) c = new immutable(C); return c.id; } Is c.id thread-safe? no! Is it constant? no! How does this help in multi-threaded applications that access c?

It is thread safe. globId is a thread-local variable. It *is* constant (the C object isn't modified) put it isn't *pure* (the return value isn't consistent). However, the fact that it is constant is just a fluke. For example, you could do this: C globalC; class C { int x = 0; this() { globalC = this; } int getX() const { globalC.x++; return x; } } C c = new C(); writeln(c.getX()); // 1 writeln(c.getX()); // 2 // etc. const (on its own) has *no* guarantees. It doesn't guarantee a consistent value (that's what pure is for) and it doesn't guarantee that the object isn't modified (that's what immutable is for). All const does in D is provide a bridge between T and immutable(T).
Sep 24 2011
parent reply Rainer Schuetze <r.sagitario gmx.de> writes:
On 9/24/2011 3:00 PM, Peter Alexander wrote:
 On 24/09/11 9:46 AM, Rainer Schuetze wrote:
 On 9/24/2011 9:30 AM, Andrei Alexandrescu wrote:
 On 9/24/11 1:12 CDT, Rainer Schuetze wrote:
 On 9/22/2011 4:10 PM, Andrei Alexandrescu wrote:
 On 9/22/11 3:02 AM, Peter Alexander wrote:
 On 22/09/11 7:04 AM, Andrei Alexandrescu wrote:
 The initial submission got junked so I resubmitted:

 http://www.reddit.com/r/programming/comments/knn5p/thoughts_on_immutability_in_d/







 Andrei

Thanks for the reddit'ing. I launched up google analytics this morning and noticed a sudden spike. That could only mean one thing :-) Out of interest, does anyone have any criticism of my post, esp. if there's any technical inaccuracies (or just disagreement?)

You could have specified that e.g. mutable state can be implemented safely with the help of a global hash table. Andrei

If this is allowed by the compiler, doesn't that break all the guarantees transitive immutability tries to make? Aren't we back to "faith based programming" this way?

Not at all. Global mutable memory is what it is to everyone. Andrei

I'm probably missing something, but what are the guarantees given by the type system, if a property is implemented by a getter function: int globId; class C { property id() const { return ++globId; } } int main() { immutable(C) c = new immutable(C); return c.id; } Is c.id thread-safe? no! Is it constant? no! How does this help in multi-threaded applications that access c?

It is thread safe. globId is a thread-local variable.

sorry, I noticed this mistake in my example too late. Using shared(int) still compiles: shared(int) globId; class C { property id() immutable { return ++globId; } } int main() { immutable(C) c = new immutable(C); return c.id; } Please notice, that I have also changed "const" to "immutable".
 It *is* constant (the C object isn't modified) put it isn't *pure* (the
 return value isn't consistent).

Yes, that's my point. What is actually guaranteed by the type system to a thread that works on an instance of type immutable(C)? It is not thread safety or constancy when reading properties, that would require them to be pure.
 However, the fact that it is constant is just a fluke. For example, you
 could do this:


 C globalC;

 class C
 {
 int x = 0;
 this() { globalC = this; }
 int getX() const { globalC.x++; return x; }
 }

 C c = new C();
 writeln(c.getX()); // 1
 writeln(c.getX()); // 2
 // etc.


 const (on its own) has *no* guarantees. It doesn't guarantee a
 consistent value (that's what pure is for) and it doesn't guarantee that
 the object isn't modified (that's what immutable is for).

 All const does in D is provide a bridge between T and immutable(T).

Sep 24 2011
parent reply Peter Alexander <peter.alexander.au gmail.com> writes:
On 24/09/11 2:39 PM, Rainer Schuetze wrote:
 Is c.id thread-safe? no! Is it constant? no! How does this help in
 multi-threaded applications that access c?

It is thread safe. globId is a thread-local variable.

sorry, I noticed this mistake in my example too late. Using shared(int) still compiles: shared(int) globId; class C { property id() immutable { return ++globId; } } int main() { immutable(C) c = new immutable(C); return c.id; } Please notice, that I have also changed "const" to "immutable".

It's still thread-safe (++ is atomic) and you still don't modify c. You need 'pure' if you want a consistent value, in which case the code would be rejected.
 It *is* constant (the C object isn't modified) put it isn't *pure* (the
 return value isn't consistent).

Yes, that's my point. What is actually guaranteed by the type system to a thread that works on an instance of type immutable(C)? It is not thread safety or constancy when reading properties, that would require them to be pure.

As I said above, it is thread-safety, although in this instance you don't even need the immutable, the shared(int) guarantees the thread safety.
Sep 24 2011
parent reply Rainer Schuetze <r.sagitario gmx.de> writes:
On 9/24/2011 6:42 PM, Peter Alexander wrote:
 On 24/09/11 2:39 PM, Rainer Schuetze wrote:
 Is c.id thread-safe? no! Is it constant? no! How does this help in
 multi-threaded applications that access c?

It is thread safe. globId is a thread-local variable.

sorry, I noticed this mistake in my example too late. Using shared(int) still compiles: shared(int) globId; class C { property id() immutable { return ++globId; } } int main() { immutable(C) c = new immutable(C); return c.id; } Please notice, that I have also changed "const" to "immutable".

It's still thread-safe (++ is atomic) and you still don't modify c. You need 'pure' if you want a consistent value, in which case the code would be rejected.
 It *is* constant (the C object isn't modified) put it isn't *pure* (the
 return value isn't consistent).

Yes, that's my point. What is actually guaranteed by the type system to a thread that works on an instance of type immutable(C)? It is not thread safety or constancy when reading properties, that would require them to be pure.

As I said above, it is thread-safety, although in this instance you don't even need the immutable, the shared(int) guarantees the thread safety.

Sorry for the bad example, here's one that is not thread-safe, and where the invariant can fail in a multi-threaded environment: shared(int) globId; class C { invariant() { assert((globId & 1) == 0); } property int id() immutable { globId = globId + 1; globId = globId + 1; return globId; } } But the details whether the operation happens to be thread safe or not is irrelevant, thread-safety is not guaranteed by the type system with immutable.
Sep 24 2011
parent reply Peter Alexander <peter.alexander.au gmail.com> writes:
On 24/09/11 4:47 PM, Rainer Schuetze wrote:
 Sorry for the bad example, here's one that is not thread-safe, and where
 the invariant can fail in a multi-threaded environment:

 shared(int) globId;

 class C
 {
 invariant() { assert((globId & 1) == 0); }
  property int id() immutable
 {
 globId = globId + 1;
 globId = globId + 1;
 return globId;
 }
 }

 But the details whether the operation happens to be thread safe or not
 is irrelevant, thread-safety is not guaranteed by the type system with
 immutable.

It's still thread safe! I think you are misunderstanding what thread safety is. http://en.wikipedia.org/wiki/Thread_safety You are right in saying that the invariant may break, but that doesn't prove that the code isn't thread safe, it just proves that you have a bad invariant. You may as well have written: invariant() { assert(false); } and then claimed that the code wasn't thread safe because immutable didn't save you. Thread safety in your example simply means that calling id() 10 times from different threads will always result in globId == 20 at the end. This isn't guaranteed by many languages. Thread safety does *not* guarantee that your invariant will hold, because your invariant not only requires thread safety but mutually exclusive access to globId around calls to id(). I should point out that immutable has absolutely no bearing in your example. Having immutable methods in a class with no members means nothing! The thread-safety comes from the shared(int) here.
Sep 24 2011
next sibling parent reply Rainer Schuetze <r.sagitario gmx.de> writes:
On 25.09.2011 04:25, Peter Alexander wrote:
 On 24/09/11 4:47 PM, Rainer Schuetze wrote:
 Sorry for the bad example, here's one that is not thread-safe, and where
 the invariant can fail in a multi-threaded environment:

 shared(int) globId;

 class C
 {
 invariant() { assert((globId & 1) == 0); }
  property int id() immutable
 {
 globId = globId + 1;
 globId = globId + 1;
 return globId;
 }
 }

 But the details whether the operation happens to be thread safe or not
 is irrelevant, thread-safety is not guaranteed by the type system with
 immutable.

It's still thread safe! I think you are misunderstanding what thread safety is. http://en.wikipedia.org/wiki/Thread_safety You are right in saying that the invariant may break, but that doesn't prove that the code isn't thread safe, it just proves that you have a bad invariant. You may as well have written: invariant() { assert(false); } and then claimed that the code wasn't thread safe because immutable didn't save you.

Grrr, another bad example, where some bad side-effects did not get unnoticed ;-)
 Thread safety in your example simply means that calling id() 10 times
 from different threads will always result in globId == 20 at the end.
 This isn't guaranteed by many languages.

This is what I wanted to show: it is also not guaranteed in D. Checking the disassembly there is nothing atomic about the operations. Even ++globId does not use a locked increment.
 Thread safety does *not* guarantee that your invariant will hold,
 because your invariant not only requires thread safety but mutually
 exclusive access to globId around calls to id().

 I should point out that immutable has absolutely no bearing in your
 example. Having immutable methods in a class with no members means
 nothing! The thread-safety comes from the shared(int) here.

Which finally brings us back to the original question: What does immutable guarantee in the face of non-pure property getter functions?
Sep 25 2011
parent Rainer Schuetze <r.sagitario gmx.de> writes:
On 26.09.2011 08:32, Jonathan M Davis wrote:
 On Monday, September 26, 2011 08:14:31 Rainer Schuetze wrote:
 Which finally brings us back to the original question: What does
 immutable guarantee in the face of non-pure property getter functions?

immutable guarantees that when an object is immutable, none of its member variables will _ever_ be altered. It guarantees _nothing_ about variables external to the object, and impure function can access pretty much anything external to an object via module level or static functions or variables, so an impure function could return literally _anything_ and could vary on every call even if the object is immutable. Any impure member function which uses values external to the object has to worry about the thread-safety of those values. The thread-safety of the object itself is guaranteed, but that's all. - Jonathan M Davis

Thanks for clarifying. My conclusion still is: if the immutable data structure implementation is unknown or complex enough that you cannot make sure the implementation of property getters are not screwed up, you are relying on faith similar to head const in C++.
Sep 26 2011
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, September 26, 2011 08:14:31 Rainer Schuetze wrote:
 Which finally brings us back to the original question: What does
 immutable guarantee in the face of non-pure property getter functions?

immutable guarantees that when an object is immutable, none of its member variables will _ever_ be altered. It guarantees _nothing_ about variables external to the object, and impure function can access pretty much anything external to an object via module level or static functions or variables, so an impure function could return literally _anything_ and could vary on every call even if the object is immutable. Any impure member function which uses values external to the object has to worry about the thread-safety of those values. The thread-safety of the object itself is guaranteed, but that's all. - Jonathan M Davis
Sep 25 2011
prev sibling parent Rainer Schuetze <r.sagitario gmx.de> writes:
On 26.09.2011 16:14, Steven Schveighoffer wrote:
 On Sat, 24 Sep 2011 04:46:07 -0400, Rainer Schuetze <r.sagitario gmx.de>
 wrote:

 On 9/24/2011 9:30 AM, Andrei Alexandrescu wrote:
 On 9/24/11 1:12 CDT, Rainer Schuetze wrote:
 On 9/22/2011 4:10 PM, Andrei Alexandrescu wrote:
 On 9/22/11 3:02 AM, Peter Alexander wrote:
 On 22/09/11 7:04 AM, Andrei Alexandrescu wrote:
 The initial submission got junked so I resubmitted:

 http://www.reddit.com/r/programming/comments/knn5p/thoughts_on_immutability_in_d/






 Andrei

Thanks for the reddit'ing. I launched up google analytics this morning and noticed a sudden spike. That could only mean one thing :-) Out of interest, does anyone have any criticism of my post, esp. if there's any technical inaccuracies (or just disagreement?)

You could have specified that e.g. mutable state can be implemented safely with the help of a global hash table. Andrei

If this is allowed by the compiler, doesn't that break all the guarantees transitive immutability tries to make? Aren't we back to "faith based programming" this way?

Not at all. Global mutable memory is what it is to everyone. Andrei

I'm probably missing something, but what are the guarantees given by the type system, if a property is implemented by a getter function: int globId; class C { property id() const { return ++globId; } } int main() { immutable(C) c = new immutable(C); return c.id; } Is c.id thread-safe? no! Is it constant? no! How does this help in multi-threaded applications that access c?

I have argued about this in the very distant past. http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=68879 We already have a logical-const system, but implementing it is simply low-performing and difficult to get right. -Steve

Thanks for the link, I didn't know it was already discussed to deeath. Good to know I'm not alone ;-) OT: It's really hard to follow long threads in the web archives, the overview of replies often gets completely out of sync. Is there a good way/place to read them?
Sep 26 2011
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, September 24, 2011 08:12:17 Rainer Schuetze wrote:
 On 9/22/2011 4:10 PM, Andrei Alexandrescu wrote:
 On 9/22/11 3:02 AM, Peter Alexander wrote:
 On 22/09/11 7:04 AM, Andrei Alexandrescu wrote:
 The initial submission got junked so I resubmitted:
 
 http://www.reddit.com/r/programming/comments/knn5p/thoughts_on_immut
 ability_in_d/
 
 
 
 Andrei

Thanks for the reddit'ing. I launched up google analytics this morning and noticed a sudden spike. That could only mean one thing :-) Out of interest, does anyone have any criticism of my post, esp. if there's any technical inaccuracies (or just disagreement?)

You could have specified that e.g. mutable state can be implemented safely with the help of a global hash table. Andrei

If this is allowed by the compiler, doesn't that break all the guarantees transitive immutability tries to make? Aren't we back to "faith based programming" this way?

In a way, yes. No, the object itself isn't altered, but by using such a hash table, you're effectively moving some of the state out of the class or struct. That state is then not regulated by const. If you did that with all of a type's member variables, then const would mean nothing. In order to truly guarantee that this isn't an issue, you have to combine const with pure. However, it _is_ a way to have an object primarily const and still have some sort of logical const. Still, it strikes me as a bad idea unless you really need it for some reason, and the fact that it makes it so that you can't use pure is definitely not desirable. - Jonathan M Davis
Sep 24 2011
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sat, 24 Sep 2011 04:46:07 -0400, Rainer Schuetze <r.sagitario gmx.de>  
wrote:

 On 9/24/2011 9:30 AM, Andrei Alexandrescu wrote:
 On 9/24/11 1:12 CDT, Rainer Schuetze wrote:
 On 9/22/2011 4:10 PM, Andrei Alexandrescu wrote:
 On 9/22/11 3:02 AM, Peter Alexander wrote:
 On 22/09/11 7:04 AM, Andrei Alexandrescu wrote:
 The initial submission got junked so I resubmitted:

 http://www.reddit.com/r/programming/comments/knn5p/thoughts_on_immutability_in_d/





 Andrei

Thanks for the reddit'ing. I launched up google analytics this morning and noticed a sudden spike. That could only mean one thing :-) Out of interest, does anyone have any criticism of my post, esp. if there's any technical inaccuracies (or just disagreement?)

You could have specified that e.g. mutable state can be implemented safely with the help of a global hash table. Andrei

If this is allowed by the compiler, doesn't that break all the guarantees transitive immutability tries to make? Aren't we back to "faith based programming" this way?

Not at all. Global mutable memory is what it is to everyone. Andrei

I'm probably missing something, but what are the guarantees given by the type system, if a property is implemented by a getter function: int globId; class C { property id() const { return ++globId; } } int main() { immutable(C) c = new immutable(C); return c.id; } Is c.id thread-safe? no! Is it constant? no! How does this help in multi-threaded applications that access c?

I have argued about this in the very distant past. http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=68879 We already have a logical-const system, but implementing it is simply low-performing and difficult to get right. -Steve
Sep 26 2011
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:

 The initial submission got junked so I resubmitted:
 
 http://www.reddit.com/r/programming/comments/knn5p/thoughts_on_immutability_in_d/

A logical const can coexist beside the other two (three) kinds of const of D. For simplicity I use the "lconst" keyword. lconst works similar to the C++ const, and it gives not troubles, because it is orthogonal to the other true consts. You are allowed to safely cast away lconst and then change the variable contents. But if you change it without casting away lconst, the compiler complains statically. Is it better to design lconst too transitive? Maybe lconst is also a "head const" just like C++. This is probably handy enough. So with a lconst array you are allowed to change its contents, but not reassign it or change its length. A lconst doesn't implicitly cast to immutable. So I think this is well doable. And probably it is useful too. But having four kinds of const in D is a lot of stuff. Maybe it is too much complex. An alternative solution to face some of the needs of lconst is to define a "trusted pure" that allows to create a pure memoization (a pure memoize). ----------------------------- Walter:
 You're right. Logical const is only a convention, since it cannot be enforced
by the compiler.

Even if it can't be enforced in 100% of the cases, I think it's still useful. So you need to look at the situation from a bit wider point of view. Bye, bearophile
Sep 22 2011
next sibling parent Peter Alexander <peter.alexander.au gmail.com> writes:
On 22/09/11 12:39 PM, bearophile wrote:
 Andrei Alexandrescu:

 The initial submission got junked so I resubmitted:

 http://www.reddit.com/r/programming/comments/knn5p/thoughts_on_immutability_in_d/

A logical const can coexist beside the other two (three) kinds of const of D. For simplicity I use the "lconst" keyword. lconst works similar to the C++ const, and it gives not troubles, because it is orthogonal to the other true consts. You are allowed to safely cast away lconst and then change the variable contents. But if you change it without casting away lconst, the compiler complains statically. Is it better to design lconst too transitive? Maybe lconst is also a "head const" just like C++. This is probably handy enough. So with a lconst array you are allowed to change its contents, but not reassign it or change its length. A lconst doesn't implicitly cast to immutable. So I think this is well doable. And probably it is useful too. But having four kinds of const in D is a lot of stuff. Maybe it is too much complex. An alternative solution to face some of the needs of lconst is to define a "trusted pure" that allows to create a pure memoization (a pure memoize).

As much as I would like logical const, I think adding it would be a mistake. Every feature, no matter how simple, adds complexity to the language: it has to be implemented, maintained, understood by tools, taught, documented... Also, if you keep adding more and more qualifiers and attributes then eventually you spend more time describing the characteristics of your program rather than the program itself.
 You're right. Logical const is only a convention, since it cannot be enforced
by the compiler.

Even if it can't be enforced in 100% of the cases, I think it's still useful. So you need to look at the situation from a bit wider point of view.

Yes, it is still useful, even if not to the compiler. It's like documentation that the compiler can semi-enforce.
Sep 22 2011
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/22/2011 4:39 AM, bearophile wrote:
 Walter:

 You're right. Logical const is only a convention, since it cannot be
 enforced by the compiler.

Even if it can't be enforced in 100% of the cases, I think it's still useful. So you need to look at the situation from a bit wider point of view.

It's worse than a half-implemented C++ feature, because the other half cannot be implemented. Even worse, when the app gets migrated to multiple threads, one inexorably falls into the tarpit of the Double Checked Locking Bug. "logical const" in C++ is faith-based programming. You'd be better off providing it as a library type that only allows read access to its state.
Sep 22 2011
parent reply Peter Alexander <peter.alexander.au gmail.com> writes:
On 23/09/11 6:48 AM, Walter Bright wrote:
 On 9/22/2011 4:39 AM, bearophile wrote:
 Walter:


I think you're exaggerating it's uselessness. It's faith-based as much as 'walking down the street assuming that the next person won't stab you' is faith-based. There's no guarantee, but 99% of the time your "faith" is well placed.
Sep 23 2011
next sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, September 23, 2011 15:58 Andrej Mitrovic wrote:
 On 9/24/11, Peter Alexander <peter.alexander.au gmail.com> wrote:
 On 23/09/11 6:48 AM, Walter Bright wrote:
 On 9/22/2011 4:39 AM, bearophile wrote:
 Walter:


I think you're exaggerating it's uselessness. It's faith-based as much as 'walking down the street assuming that the next person won't stab you' is faith-based. There's no guarantee, but 99% of the time your "faith" is well placed.

So then don't use const if u need caching and use convention if your faith is well placed!

const in C++ really does help to catch bugs. It's definitely better than nothing. I do _not_ think that it is worthless like Walter at least gives the impression that he thinks. Now, I _do_ think that on the whole, D's const is better. The transitiveness of const is a major improvement IMHO, and the caching thing, while annoying, isn't that big a loss in my experience. I expect that with Peter's gaming background, it's much more of an issue for him. I think that it's at least theoretically possible to get a caching mechanism to work with const, which would overcome that portion of the logical const problem, but the question is how best to do it and whether the added complication is worth the cost. Certainly, it's the sort of thing that we should look into for D3 when we get that far. But for now, on the whole, D's const is a definite improvement over C++'s const, and you just don't use const in D in quite as many places as you would have in C++. But while C++'s const is not as good as D's const, it's still very worthwhile IMHO. - Jonathan M Davis
Sep 23 2011
next sibling parent reply Mehrdad <wfunction hotmail.com> writes:
On 9/23/2011 4:13 PM, Jonathan M Davis wrote:
 On Friday, September 23, 2011 15:58 Andrej Mitrovic wrote:
 On 9/24/11, Peter Alexander<peter.alexander.au gmail.com>  wrote:
 On 23/09/11 6:48 AM, Walter Bright wrote:
 On 9/22/2011 4:39 AM, bearophile wrote:
 Walter:


It's faith-based as much as 'walking down the street assuming that the next person won't stab you' is faith-based. There's no guarantee, but 99% of the time your "faith" is well placed.

faith is well placed!

nothing. I do _not_ think that it is worthless like Walter at least gives the impression that he thinks. Now, I _do_ think that on the whole, D's const is better. The transitiveness of const is a major improvement IMHO, and the caching thing, while annoying, isn't that big a loss in my experience. I expect that with Peter's gaming background, it's much more of an issue for him. I think that it's at least theoretically possible to get a caching mechanism to work with const, which would overcome that portion of the logical const problem, but the question is how best to do it and whether the added complication is worth the cost. Certainly, it's the sort of thing that we should look into for D3 when we get that far. But for now, on the whole, D's const is a definite improvement over C++'s const, and you just don't use const in D in quite as many places as you would have in C++. But while C++'s const is not as good as D's const, it's still very worthwhile IMHO. - Jonathan M Davis

though I'm not sure about others (would love to hear otherwise)...
Sep 23 2011
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 09/24/2011 01:34 AM, Mehrdad wrote:
 On 9/23/2011 4:13 PM, Jonathan M Davis wrote:
 On Friday, September 23, 2011 15:58 Andrej Mitrovic wrote:
 On 9/24/11, Peter Alexander<peter.alexander.au gmail.com> wrote:
 On 23/09/11 6:48 AM, Walter Bright wrote:
 On 9/22/2011 4:39 AM, bearophile wrote:
 Walter:


It's faith-based as much as 'walking down the street assuming that the next person won't stab you' is faith-based. There's no guarantee, but 99% of the time your "faith" is well placed.

faith is well placed!

nothing. I do _not_ think that it is worthless like Walter at least gives the impression that he thinks. Now, I _do_ think that on the whole, D's const is better. The transitiveness of const is a major improvement IMHO, and the caching thing, while annoying, isn't that big a loss in my experience. I expect that with Peter's gaming background, it's much more of an issue for him. I think that it's at least theoretically possible to get a caching mechanism to work with const, which would overcome that portion of the logical const problem, but the question is how best to do it and whether the added complication is worth the cost. Certainly, it's the sort of thing that we should look into for D3 when we get that far. But for now, on the whole, D's const is a definite improvement over C++'s const, and you just don't use const in D in quite as many places as you would have in C++. But while C++'s const is not as good as D's const, it's still very worthwhile IMHO. - Jonathan M Davis

though I'm not sure about others (would love to hear otherwise)...

If you are trying to use const in the same way as C++ const and you are not using immutable in combination with const then you probably don't use the feature properly. I don't know for sure if this is the case though. Is it?
Sep 24 2011
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/23/2011 4:13 PM, Jonathan M Davis wrote:
 But while C++'s const is not as good as D's const, it's still very worthwhile
 IMHO.

To me it's like buffer overflows. 99% of C/C++ code doesn't have buffer overflows, and is perfectly reliable. But if someone hands you a 1,000,000 line program and asks "ensure there are no buffer overflows" what are you going to do? What are you going to do when Junior Programmer makes a patch to your perfectly correct C/C++ code base, and now it has a subtle overflow bug? Start all over with the review process? This is not an idle question, as a major focus of C static analysis tools is to detect buffer overflows, and people spend a lot of effort & money on them. Faith based programming works in the small, but programs grow ever larger in size and complexity. Switching from faith to static guarantees is a much more scalable technique. And where C++ const is really, really useless is when it comes to multithreaded programming.
Sep 23 2011
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/23/2011 5:31 PM, Jonathan M Davis wrote:
 I have to specifically circumvent the compiler to be
 able to alter const stuff.

Nope, not with 'mutable' you don't have to circumvent anything. Just change it.
Sep 23 2011
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/23/2011 6:55 PM, Jonathan M Davis wrote:
 True, but it doesn't just happen. You have to choose to make a variable
 mutable.

Which you *must* do for logical const. And, of course, anything beyond the first level is not const at all, and there's NO WAY to say it is const.
 _Some_ effort must be put in to circumvent const. Until you do that,
 const protects it from be changed.

There's no way to detect who or what is changing it.
 By no means am I claiming that C++'s const is without flaws. I'm just claiming
 that it's not worthless, and you seem to be claiming that it's worthless.

I think it is worthless because: 1. a number of C++ programmers I've talked to who relied on being able to change const objects and insisted that was a feature. 2. the pervasive misconceptions about what C++ const guarantees and what it doesn't, even among C++ committee members. 3. the complete uselessness C++ const has for multithreaded programming. 4. the pervasiveness of the Double Checked Locking Bug, which is one of the consequences of (3). 5. it's head-const only. Anything beyond one level of indirection is completely const-free. Only trivial data structures are one level.
Sep 23 2011
parent Mehrdad <wfunction hotmail.com> writes:
On 9/23/2011 8:11 PM, Jonathan M Davis wrote:
 On Friday, September 23, 2011 19:42:24 Walter Bright wrote:
 On 9/23/2011 6:55 PM, Jonathan M Davis wrote:
 True, but it doesn't just happen. You have to choose to make a variable
 mutable.

first level is not const at all, and there's NO WAY to say it is const.
 _Some_ effort must be put in to circumvent const. Until you do that,
 const protects it from be changed.

 By no means am I claiming that C++'s const is without flaws. I'm just
 claiming that it's not worthless, and you seem to be claiming that it's
 worthless.

1. a number of C++ programmers I've talked to who relied on being able to change const objects and insisted that was a feature. 2. the pervasive misconceptions about what C++ const guarantees and what it doesn't, even among C++ committee members. 3. the complete uselessness C++ const has for multithreaded programming. 4. the pervasiveness of the Double Checked Locking Bug, which is one of the consequences of (3). 5. it's head-const only. Anything beyond one level of indirection is completely const-free. Only trivial data structures are one level.

makes C++'s const worthless. Const has caught bugs in my code for me. I have found it to be useful in the projects that I've worked on. So, we're obviously just going to have to agree to disagree on this, and I think that a lot of C++ programmers are going to disagree with you (including many who understand exactly what const does and doesn't guarantee). - Jonathan M Davis

wouldn't believe anyone for 1 second if he said he's used const in his code and it never caught an error for him (or if it introduced more than it caught).
Sep 23 2011
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 09/23/11 17:46, Peter Alexander wrote:
 On 23/09/11 6:48 AM, Walter Bright wrote:
 On 9/22/2011 4:39 AM, bearophile wrote:
 Walter:


I think you're exaggerating it's uselessness. It's faith-based as much as 'walking down the street assuming that the next person won't stab you' is faith-based.

... in Mogadishu :o). Andrei
Sep 23 2011
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/23/2011 3:46 PM, Peter Alexander wrote:
 On 23/09/11 6:48 AM, Walter Bright wrote:
 On 9/22/2011 4:39 AM, bearophile wrote:
 Walter:


I think you're exaggerating it's uselessness. It's faith-based as much as 'walking down the street assuming that the next person won't stab you' is faith-based. There's no guarantee, but 99% of the time your "faith" is well placed.

You can define an object with private only access to its data members, and do logical const that way without needing faith.
Sep 23 2011
prev sibling next sibling parent reply Peter Alexander <peter.alexander.au gmail.com> writes:
On 23/09/11 11:58 PM, Andrej Mitrovic wrote:
 On 9/24/11, Peter Alexander<peter.alexander.au gmail.com>  wrote:
 On 23/09/11 6:48 AM, Walter Bright wrote:
 On 9/22/2011 4:39 AM, bearophile wrote:
 Walter:


I think you're exaggerating it's uselessness. It's faith-based as much as 'walking down the street assuming that the next person won't stab you' is faith-based. There's no guarantee, but 99% of the time your "faith" is well placed.

So then don't use const if u need caching and use convention if your faith is well placed!

That's what I do :-) I only use const/immutable for concurrency. Nothing else.
Sep 24 2011
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/24/2011 6:03 AM, Peter Alexander wrote:
 I only use const/immutable for concurrency. Nothing else.

How do you avoid race conditions when setting logical const values?
Sep 24 2011
next sibling parent reply "dame" <damesureurnotme yousuck.gov> writes:
Walter Bright wrote:
 On 9/24/2011 6:03 AM, Peter Alexander wrote:
 I only use const/immutable for concurrency. Nothing else.

How do you avoid race conditions when setting logical const values?

Is that important?
Sep 24 2011
parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/24/2011 11:00 PM, dame wrote:
 Walter Bright wrote:
 On 9/24/2011 6:03 AM, Peter Alexander wrote:
 I only use const/immutable for concurrency. Nothing else.

How do you avoid race conditions when setting logical const values?

Is that important?

If you have a concurrent data structure, it's critical.
Sep 24 2011
prev sibling parent Peter Alexander <peter.alexander.au gmail.com> writes:
On 25/09/11 4:49 AM, Walter Bright wrote:
 On 9/24/2011 6:03 AM, Peter Alexander wrote:
 I only use const/immutable for concurrency. Nothing else.

How do you avoid race conditions when setting logical const values?

You can't and don't. That's not what logical const is for. That's what physical const is for, and it does a great job at that. Can I just be clear: I am not anti-physical const. I'm just also not anti-logical const, which D is. Logical const is best for functional programming and physical const is best for concurrent programming. Both are important.
Sep 25 2011
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 23 Sep 2011 20:13:39 -0400, Walter Bright  
<newshound2 digitalmars.com> wrote:

 On 9/23/2011 4:13 PM, Jonathan M Davis wrote:
 But while C++'s const is not as good as D's const, it's still very  
 worthwhile
 IMHO.

To me it's like buffer overflows. 99% of C/C++ code doesn't have buffer overflows, and is perfectly reliable. But if someone hands you a 1,000,000 line program and asks "ensure there are no buffer overflows" what are you going to do? What are you going to do when Junior Programmer makes a patch to your perfectly correct C/C++ code base, and now it has a subtle overflow bug? Start all over with the review process? This is not an idle question, as a major focus of C static analysis tools is to detect buffer overflows, and people spend a lot of effort & money on them. Faith based programming works in the small, but programs grow ever larger in size and complexity. Switching from faith to static guarantees is a much more scalable technique. And where C++ const is really, really useless is when it comes to multithreaded programming.

D's const system is also not impervious to Junior mistakes (even without casts!), but it's certainly better than C++. The truth is, the only time you get guarantees with D is when you have pure functions and immutable data. Const doesn't guarantee anything. Even immutable functions still can access global state. -Steve
Sep 26 2011
prev sibling next sibling parent travert phare.normalesup.org (Christophe) writes:
bearophile , dans le message (digitalmars.D:145005), a écrit :

 So with a lconst array you are allowed to change its contents, but not 
 reassign it or change its length. A lconst doesn't implicitly cast to 
 immutable.

A solution to your problems could be to use a headconst keyword or library tool, or, even more powerful but probably much harder to implement, a mutable keyword. const(mutable(int)[]) mutable for an array or a pointer would mean you can change what is pointed, even if the array or pointer is const. It could be forbidden for fields. This could be useful to lazily fill up fields of const objects. However, if this has to break a fraction of the power of D's constness, it would not be desirable. -- Christophe
Sep 23 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 9/24/11, Peter Alexander <peter.alexander.au gmail.com> wrote:
 On 23/09/11 6:48 AM, Walter Bright wrote:
 On 9/22/2011 4:39 AM, bearophile wrote:
 Walter:


I think you're exaggerating it's uselessness. It's faith-based as much as 'walking down the street assuming that the next person won't stab you' is faith-based. There's no guarantee, but 99% of the time your "faith" is well placed.

So then don't use const if u need caching and use convention if your faith is well placed!
Sep 23 2011
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 23 Sep 2011 20:05:16 -0400, Walter Bright  
<newshound2 digitalmars.com> wrote:

 On 9/23/2011 3:46 PM, Peter Alexander wrote:
 On 23/09/11 6:48 AM, Walter Bright wrote:
 On 9/22/2011 4:39 AM, bearophile wrote:
 Walter:


I think you're exaggerating it's uselessness. It's faith-based as much as 'walking down the street assuming that the next person won't stab you' is faith-based. There's no guarantee, but 99% of the time your "faith" is well placed.

You can define an object with private only access to its data members, and do logical const that way without needing faith.

const functions still require faith that nobody used a global. -Steve
Sep 26 2011
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, September 23, 2011 16:34 Mehrdad wrote:
 So far, the 5% of the code it breaks has made it 95% worthless for me,
 though I'm not sure about others (would love to hear otherwise)...

But _what_ does it break? The lack of logical const is definitely limiting, but at the moment, I can't think of even one case where transitive const is a big isue. The only issues with const that I can think of (aside from quality of implementation issues with the current compiler) are the lack of logical const and the issues with having a non-const reference to a const object (which Rebindable fixes and Michel Fortin's propose language change would do an even better job of fixing if it ever gets accepted). You seem to have an issue specifically with the transitivity of const, and I don't understand what the problems are that transitive const is causing. - Jonathan M Davis
Sep 23 2011
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, September 23, 2011 17:13 Walter Bright wrote:
 On 9/23/2011 4:13 PM, Jonathan M Davis wrote:
 But while C++'s const is not as good as D's const, it's still very
 worthwhile IMHO.

To me it's like buffer overflows. 99% of C/C++ code doesn't have buffer overflows, and is perfectly reliable. But if someone hands you a 1,000,000 line program and asks "ensure there are no buffer overflows" what are you going to do? What are you going to do when Junior Programmer makes a patch to your perfectly correct C/C++ code base, and now it has a subtle overflow bug? Start all over with the review process? This is not an idle question, as a major focus of C static analysis tools is to detect buffer overflows, and people spend a lot of effort & money on them. Faith based programming works in the small, but programs grow ever larger in size and complexity. Switching from faith to static guarantees is a much more scalable technique. And where C++ const is really, really useless is when it comes to multithreaded programming.

No, C++ does not give you an ironclad guarantee about correctness, and yes, it's absolutely useless for multi-threaded programming, but what it _does_ give you is still valuable. For instance, if I choose to use const_iterator instead of iterator, then when I screw up the call to <algorithm>'s copy function and mix up the iterators, the compiler will catch it and complain. When I try and call a non-const function on a const object, the compiler will complain. It will help me find errors in my code. And no, it won't help me find every const-related error, and no, there is no absolute guarantee that a const function _won't_ alter the object, but in general, it actually doesn't alter the object, and I have to specifically circumvent the compiler to be able to alter const stuff. Certain classes of bugs are caught because of const in C++. Even if the compiler can't take advantage of it for optimizations or whatnot, and even if it doesn't give as strong guarantees to the programmer as might be desirable, it _does_ help the programmer catch and prevent bugs. I completely agree with you that having static guarantees is better, but I don't think that the faith-based guarantees of C++'s const are worthless, just worse. - Jonathan M Davis
Sep 23 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, September 23, 2011 18:39:19 Walter Bright wrote:
 On 9/23/2011 5:31 PM, Jonathan M Davis wrote:
 I have to specifically circumvent the compiler to be
 able to alter const stuff.

Nope, not with 'mutable' you don't have to circumvent anything. Just change it.

True, but it doesn't just happen. You have to choose to make a variable mutable. _Some_ effort must be put in to circumvent const. Until you do that, const protects it from be changed. By no means am I claiming that C++'s const is without flaws. I'm just claiming that it's not worthless, and you seem to be claiming that it's worthless. - Jonathan M Davis
Sep 23 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, September 23, 2011 19:42:24 Walter Bright wrote:
 On 9/23/2011 6:55 PM, Jonathan M Davis wrote:
 True, but it doesn't just happen. You have to choose to make a variable
 mutable.

Which you *must* do for logical const. And, of course, anything beyond the first level is not const at all, and there's NO WAY to say it is const.
 _Some_ effort must be put in to circumvent const. Until you do that,
 const protects it from be changed.

There's no way to detect who or what is changing it.
 By no means am I claiming that C++'s const is without flaws. I'm just
 claiming that it's not worthless, and you seem to be claiming that it's
 worthless.

1. a number of C++ programmers I've talked to who relied on being able to change const objects and insisted that was a feature. 2. the pervasive misconceptions about what C++ const guarantees and what it doesn't, even among C++ committee members. 3. the complete uselessness C++ const has for multithreaded programming. 4. the pervasiveness of the Double Checked Locking Bug, which is one of the consequences of (3). 5. it's head-const only. Anything beyond one level of indirection is completely const-free. Only trivial data structures are one level.

Well, I grant you that all of those are issues, but I don't think that they makes C++'s const worthless. Const has caught bugs in my code for me. I have found it to be useful in the projects that I've worked on. So, we're obviously just going to have to agree to disagree on this, and I think that a lot of C++ programmers are going to disagree with you (including many who understand exactly what const does and doesn't guarantee). - Jonathan M Davis
Sep 23 2011
prev sibling parent "Marco Leise" <Marco.Leise gmx.de> writes:
Am 24.09.2011, 07:28 Uhr, schrieb Mehrdad <wfunction hotmail.com>:

 On 9/23/2011 8:11 PM, Jonathan M Davis wrote:
 On Friday, September 23, 2011 19:42:24 Walter Bright wrote:
 On 9/23/2011 6:55 PM, Jonathan M Davis wrote:
 True, but it doesn't just happen. You have to choose to make a  
 variable
 mutable.

the first level is not const at all, and there's NO WAY to say it is const.
 _Some_ effort must be put in to circumvent const. Until you do that,
 const protects it from be changed.

 By no means am I claiming that C++'s const is without flaws. I'm just
 claiming that it's not worthless, and you seem to be claiming that  
 it's
 worthless.

1. a number of C++ programmers I've talked to who relied on being able to change const objects and insisted that was a feature. 2. the pervasive misconceptions about what C++ const guarantees and what it doesn't, even among C++ committee members. 3. the complete uselessness C++ const has for multithreaded programming. 4. the pervasiveness of the Double Checked Locking Bug, which is one of the consequences of (3). 5. it's head-const only. Anything beyond one level of indirection is completely const-free. Only trivial data structures are one level.

they makes C++'s const worthless. Const has caught bugs in my code for me. I have found it to be useful in the projects that I've worked on. So, we're obviously just going to have to agree to disagree on this, and I think that a lot of C++ programmers are going to disagree with you (including many who understand exactly what const does and doesn't guarantee). - Jonathan M Davis

wouldn't believe anyone for 1 second if he said he's used const in his code and it never caught an error for him (or if it introduced more than it caught).

Of course it does, because these bugs were logical bugs, an area where logical const is a perfect match. (You don't need guarantees, just the semantic analysis at compile time.)
Sep 28 2011