www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Why do we have transitive const, again?

reply Mehrdad <wfunction hotmail.com> writes:
I can't find the thread, but I remember someone (bearophile?) mentioned 
that the reason we have transitive const is to support purity.

I don't think I understand why this is necessary, though -- could 
someone please explain why we have transitive const, and what problems 
it fixes?

Thanks!
Sep 21 2011
next sibling parent reply Jesse Phillips <jessekphillips+d gmail.com> writes:
On Wed, 21 Sep 2011 10:15:31 -0700, Mehrdad wrote:

 I can't find the thread, but I remember someone (bearophile?) mentioned
 that the reason we have transitive const is to support purity.
 
 I don't think I understand why this is necessary, though -- could
 someone please explain why we have transitive const, and what problems
 it fixes?
 
 Thanks!

I came across this blog earlier, it may hold the answers you seek: http://www.reddit.com/tb/kkwch "One of the core difficulties in concurrent programming is trying to avoid the simultaneous reading and writing of data. Like with functional programming, concurrent programming is a lot easier when data can't change -- if you have no writes then you can't possibly have simultaneously reading and writing. However, unlike functional programming, logical const just doesn't cut it. If you were to give a reference to an instance of my Matrix class to two threads, and ask them both to compute the determinant then you could end up with an ugly race condition due to the memory writes in the caching mechanism. Here, physical immutability really does matter."
Sep 21 2011
parent reply Mehrdad <wfunction hotmail.com> writes:
On 9/21/2011 8:21 PM, Jesse Phillips wrote:
 On Wed, 21 Sep 2011 10:15:31 -0700, Mehrdad wrote:

 I can't find the thread, but I remember someone (bearophile?) mentioned
 that the reason we have transitive const is to support purity.

 I don't think I understand why this is necessary, though -- could
 someone please explain why we have transitive const, and what problems
 it fixes?

 Thanks!

http://www.reddit.com/tb/kkwch "One of the core difficulties in concurrent programming is trying to avoid the simultaneous reading and writing of data. Like with functional programming, concurrent programming is a lot easier when data can't change -- if you have no writes then you can't possibly have simultaneously reading and writing. However, unlike functional programming, logical const just doesn't cut it. If you were to give a reference to an instance of my Matrix class to two threads, and ask them both to compute the determinant then you could end up with an ugly race condition due to the memory writes in the caching mechanism. Here, physical immutability really does matter."

you mind clarifying? Why does having transitive immutable also imply that we /must/ have transitive const?
Sep 23 2011
parent mta`chrono <chrono mta-international.net> writes:
 I don't see why immutability has anything to do with constness... would
 you mind clarifying? Why does having transitive immutable also imply
 that we /must/ have transitive const?

One man's variable is other man's const. foobar(const(char)[] data) { } immutable(char)[] data = "...."; foobar(data);
Sep 23 2011
prev sibling next sibling parent reply Peter Alexander <peter.alexander.au gmail.com> writes:
On 21/09/11 6:15 PM, Mehrdad wrote:
 I can't find the thread, but I remember someone (bearophile?) mentioned
 that the reason we have transitive const is to support purity.

 I don't think I understand why this is necessary, though -- could
 someone please explain why we have transitive const, and what problems
 it fixes?

 Thanks!

It's mostly for concurrent programming. If I pass an immutable(T) reference type to another thread then I need to be guaranteed that the object is entirely immutable. If it weren't for transitive const/immutable, this would be possible: class Foo { Foo m_ref; this() { m_ref = this; } Foo get() immutable { return m_ref; } } immutable(Foo) foo = new Foo(); Foo surprise = foo.get(); // un-immutable-ified!
Sep 22 2011
next sibling parent reply Mehrdad <wfunction hotmail.com> writes:
Er, you answered a question about const with an answer about immutable. :\

My point is, what in the world does transitive const have to do with 
transitive immutable?
Can't you have immutable(T) be transitive while const(T) being "normal", 
as in C/C++? If not, why not?

On 9/22/2011 10:36 AM, Peter Alexander wrote:
 On 21/09/11 6:15 PM, Mehrdad wrote:
 I can't find the thread, but I remember someone (bearophile?) mentioned
 that the reason we have transitive const is to support purity.

 I don't think I understand why this is necessary, though -- could
 someone please explain why we have transitive const, and what problems
 it fixes?

 Thanks!

It's mostly for concurrent programming. If I pass an immutable(T) reference type to another thread then I need to be guaranteed that the object is entirely immutable. If it weren't for transitive const/immutable, this would be possible: class Foo { Foo m_ref; this() { m_ref = this; } Foo get() immutable { return m_ref; } } immutable(Foo) foo = new Foo(); Foo surprise = foo.get(); // un-immutable-ified!

Sep 23 2011
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 09/23/2011 08:21 PM, Mehrdad wrote:
 Er, you answered a question about const with an answer about immutable. :\

 My point is, what in the world does transitive const have to do with
 transitive immutable?
 Can't you have immutable(T) be transitive while const(T) being "normal",
 as in C/C++? If not, why not?

const(T) / \ / \ / \ / \ / \ immutable(T) T const(T) is a common 'supertype' of immutable(T) and T. D const means: This could be immutable or mutable. You are not allowed to change it because it might be immutable. C++ const means: This is head-const and you are not allowed to call any non-const member functions on that object, well, unless you cast away const. The two concepts are different. D const is transitive because immutable is transitive.
Sep 23 2011
prev sibling next sibling parent reply Mehrdad <wfunction hotmail.com> writes:
On 9/23/2011 11:47 AM, Jonathan M Davis wrote:
 ...You'd have to duplicate functions all over the place... - Jonathan 
 M Davis 

Can't you avoid that trivially with templates?
Sep 23 2011
next sibling parent reply Mehrdad <wfunction hotmail.com> writes:
On 9/23/2011 2:55 PM, Jonathan M Davis wrote:
 On Friday, September 23, 2011 14:37 Mehrdad wrote:
 On 9/23/2011 11:47 AM, Jonathan M Davis wrote:
 ...You'd have to duplicate functions all over the place... - Jonathan
 M Davis



 Templated functions can't be
 virtual. And even if they _could_ be, that still requires that programmers
 template or duplicate functions all over the place. It not only increases the
 amount of bloat in the binary, but it creates more work for the programmer.

in Phobos? I thought I always said functions shouldn't be templated, but everyone said it's OK because (1) that's how it is in C++, (2) it's faster, (3) etc., etc... I'm really confused by your [seemingly] contradictory reasoning. :\
 Honestly, I don't understand what the problem with transitive const is.
 What are you trying to do that the transitiveness of const causes issues? I
 just don't see the problem.

 - Jonathan M Davis

Haven't we already had enough complaints on the newsgroup about the problems with const? Are they all bogus or something?
Sep 23 2011
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/23/11 5:27 PM, Mehrdad wrote:
 Haven't we already had enough complaints on the newsgroup about the
 problems with const? Are they all bogus or something?

Hm, this made me realize something. Nobody complained about D's const since a good while ago. Probably that's because many related bugs have been fixed - but we've still got a ways to go. Andrei
Sep 23 2011
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
IMO immutable has taken a step *backward* a few releases ago,
and that's about all I've thought about it.

immutable string a = "lol";

auto b = replace(a, "lol", "rofl"); // used to work, now doesn't.


The thing is the immutable works well with normal functions, but
not with range templates. Ugh.



Other than that, the system kinda works, but I find I don't
use it very often, especially in classes. Perhaps that will
change with inout being finished.
Sep 23 2011
parent Jerry Quinn <jlquinn optonline.net> writes:
Adam D. Ruppe Wrote:

 IMO immutable has taken a step *backward* a few releases ago,
 and that's about all I've thought about it.
 
 immutable string a = "lol";
 
 auto b = replace(a, "lol", "rofl"); // used to work, now doesn't.

This works for me in 2.055. Jerry
Sep 23 2011
prev sibling parent reply Mehrdad <wfunction hotmail.com> writes:
On 9/23/2011 3:56 PM, Jonathan M Davis wrote:
 The complaints have generally been about the lack of logical const and 
 the inability to cast away const and modify variables _not_ about 
 transitiveness. I'm not say that there have been _no_ complaints about 
 the transitiveness about const, but I can't recall even _one_ issue 
 with it at the moment. It's the lack of logical const that's generally 
 complained about and has shown itself to be a major blocker for const 
 in some cases. - Jonathan M Davis 

But the only reason logical const is an issue is indeed the fact that const is transitive. To illustrate, I run into problem almost every other time I use D, and to me it's *only* a problem because source is const: class MyRange : InputRange!char { char peeked; InputRange!char source; char front() const { // How do I lazy-load the value? if (peeked == '\0') { peeked = source.front; // ERROR, popFront isn't const... source.popFront(); } return peeked; } } If this isn't because of transitivity, then what is it? If only source wasn't implicitly const (and it wouldn't be in C++, since it'd be a const pointer to a non-const object) then this would be a piece of cake. I run into this problem and similar ones so often that it's driven me away from D, as much as I was a fan. If you have a nice solution then please let me know.
Sep 23 2011
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 09/23/11 20:52, Mehrdad wrote:
 On 9/23/2011 3:56 PM, Jonathan M Davis wrote:
 The complaints have generally been about the lack of logical const and
 the inability to cast away const and modify variables _not_ about
 transitiveness. I'm not say that there have been _no_ complaints about
 the transitiveness about const, but I can't recall even _one_ issue
 with it at the moment. It's the lack of logical const that's generally
 complained about and has shown itself to be a major blocker for const
 in some cases. - Jonathan M Davis

But the only reason logical const is an issue is indeed the fact that const is transitive. To illustrate, I run into problem almost every other time I use D, and to me it's *only* a problem because source is const: class MyRange : InputRange!char { char peeked; InputRange!char source; char front() const { // How do I lazy-load the value? if (peeked == '\0') { peeked = source.front; // ERROR, popFront isn't const... source.popFront(); } return peeked; } } If this isn't because of transitivity, then what is it? If only source wasn't implicitly const (and it wouldn't be in C++, since it'd be a const pointer to a non-const object) then this would be a piece of cake. I run into this problem and similar ones so often that it's driven me away from D, as much as I was a fan. If you have a nice solution then please let me know.

This strikes me as a pretext. If you frame that obscure matter as a showstopper, you'll have no trouble finding another one the moment you're given a solution. Andrei
Sep 23 2011
next sibling parent Mehrdad <wfunction hotmail.com> writes:
On 9/23/2011 7:21 PM, Andrei Alexandrescu wrote:
 On 09/23/11 20:52, Mehrdad wrote:
 I run into this problem and similar ones so often that it's driven me 
 away from D, as much as I was a fan. If you have a nice solution then 
 please let me know.

This strikes me as a pretext. If you frame that obscure matter as a showstopper, you'll have no trouble finding another one the moment you're given a solution. Andrei

o_O... What's so "obscure", exactly? Are you asking for some sort of "proof" for the fact that that problem was a showstopper for me or something?
Sep 23 2011
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, September 23, 2011 19:43:53 Mehrdad wrote:
 On 9/23/2011 7:21 PM, Andrei Alexandrescu wrote:
 On 09/23/11 20:52, Mehrdad wrote:
 I run into this problem and similar ones so often that it's driven me
 away from D, as much as I was a fan. If you have a nice solution then
 please let me know.

This strikes me as a pretext. If you frame that obscure matter as a showstopper, you'll have no trouble finding another one the moment you're given a solution. Andrei

o_O... What's so "obscure", exactly? Are you asking for some sort of "proof" for the fact that that problem was a showstopper for me or something?

The problem is easy enough to get around - just don't use const when you need lazy loading or caching (though obviously that restriction is annoying). The fact that _one_ feature in the language does not work the way that you'd like it to (and that that issue only occurs when you use it in a particular way which many people would never try to do) would be a showstopper for you using the language (especially when there's a simple, if annoying, workaround) would seem to indicate that it doesn't take much for you to give up on D (or whatever language you might be trying to use). So, even if this one issue were fixed, it presumably wouldn't take much for you decide that some other relatively small item in the language was a showstopper. I believe that that's all he's really saying. - Jonathan M Davis
Sep 23 2011
prev sibling next sibling parent reply Mehrdad <wfunction hotmail.com> writes:
On 9/23/2011 7:09 PM, Jonathan M Davis wrote:
 Then the lack of logical const is really your issue, not the 
 transivity. Granted, logical const would be less of an issue if const 
 weren't transitive, but ultimately, it's the fact that there is no way 
 to alter a const variable without subverting the type system that's 
 your problem.

(inability to have logical const, or whatever you want to call it, I don't really care what it's called) is the presence of transitive const. I'm not talking about the problem, but the cause.
 If you don't care about purity, it _is_ possible to have caching and 
 lazy loading, but it's a bit ugly IMHO.

would be a non-issue.
 ...

sorry. :(
 So, is the fact that D's const does not allow for any kind of caching 
 or lazy loading the only issue that you're really seeing with const 
 (beyond implementation issues)?

issue. i.e. this class reads from a terminal, and it's not like I can make it read at a different time, since doing so at the wrong time would cause it to deadlock. So I have to grab the input on the first fetch, and it's not like I'm doing this to optimize anything... the code simply _won't function_ if I don't do this.
 It _is_ an issue, and the transivity does make it worse, since more 
 stuff is const than would be otherwise, but are there other issues 
 beyond that?

 I think that it would be great if we could find a solution to lazy 
 loading and caching so that it works with const, but I fear that at 
 this point, that that is relegated to D3 unless someone can come up 
 with a very clever solution that is backwards compatible.

this come up often enough to make D kind of annoying to use...
Sep 23 2011
parent Mehrdad <wfunction hotmail.com> writes:
Also, another problem I remembered about const:

If you have a const object, you can't have an invariant() that calls 
something impure (or something like that -- I forget the details, it was 
a while ago). Which was pretty darn annoying when I was trying to use 
D's DBC features, which seemed to again conflict with the the 
transitivity of const.

I'll post more issues as I remember them. There certainly wasn't just 1.

See below for inline reply.

-------------------

On 9/23/2011 8:08 PM, Jonathan M Davis wrote:
 Many, many people _never_ try and lazy load or cache variables like 
 you're trying to do. So, there are many, many people that this will 
 never affect 

then please ignore this entire post; it was my mistake.
 Obviously, it _will_ affect people but not enough that it would 
 cripple D's chances of catching on.

tells me that isn't quite enough. YMMV.
 Also, since all you have to do to work around the issue is to not use 
 const in this particular case (and there are already tons of 
 programmers who never use const and have no interest in it),and you're 
 fine, I don't see how this can be a showstopper for adopting the language.

find this reasoning convincing, since I don't (and I don't think others do either).
 Yes, it's annoying, but there's a workaround which doesn't affect 
 performance at all,

see how that's relevant, because honestly, the word "performance" wasn't even in my /mind/ when I was thinking about this problem. All I wanted was to _compile_ *verifiably correct* code, which failed pretty darn miserably, due to the const issues. I couldn't care less about performance when I was writing my code.
 and if something like this is all it takes for you to decide that 
 you're not going to use a particular language, then it's going to be 
 hard to get you to use _any_ language.

otherwise? Feel free to believe that, if it makes sense with your reasoning.
 They _all_ have issues of one sort or another, if nothing else because 
 every language makes its own share of tradeoffs based on its goals.

tradeoffs are NOT like other languages' tradeoffs. Widely-used languages (C++, Python, C#, whatever) do NOT have half-baked (or even 95%-baked) features. They have features that work 100% of the time. Sure, they may be incomplete and they certainly have more room for improvement, but _what they *already* have_ works in EVERY situation. If you ever wondered what people meant on programmers.se when they said "C++ has a better thought-out type system", I hope you now know why. They did NOT mean that it has better features. Or that the compilers are of better quality. They were saying that the rules are self-consistent and they *work*. That is, _regardless_ of the compiler quality, the features of the *language* itself work in EVERY situation. D, on the other hand, tries to appeal to everyone but instead has supposedly awesome features (e.g. transitive const) that DON'T work 100% of the time. They only work 95% of the time. You might refuse to believe this, but I'm convinced that this **IS** the reason why it's not being adopted as fast as you'd want it to be. You can continue to justify it as "but it works for 95% of people!" but the fact of the matter is that we've seen otherwise. Believe me, I want to see D get adopted too, but my brain is telling me that there HAS to be a reason it hasn't -- and that reason isn't the compiler bugs or anything of that sort, but the language itself. P.S. I really hope people don't take this as a C++ fanboy ranting about D... not only am I not a fan of C++ (I pretty much hate the language), and it should be obvious (if not from my previous posts, at least from how much I've tried to promote D on StackOverflow) that I indeed do like D, and I've tried to suggest it to people as often as I've been able to. But over time, I've come to realize some of the reasons people like C++ as opposed to D, so I'm trying to point them out here so that they might be helpful. Hopefully they make sense.
Sep 23 2011
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 9/23/2011 6:52 PM, Mehrdad wrote:

 To illustrate, I run into problem almost every other time I use D, and to me
 it's *only* a problem because source is const:

 class MyRange : InputRange!char
 {
 char peeked;
 InputRange!char source;
 char front() const

char front() // fixed!
 {
 // How do I lazy-load the value?
 if (peeked == '\0')
 {
 peeked = source.front;
 // ERROR, popFront isn't const...
 source.popFront();
 }
 return peeked;
 }
 }

Sep 24 2011
prev sibling parent Jason House <jason.james.house gmail.com> writes:
Mehrdad Wrote:

 On 9/23/2011 11:47 AM, Jonathan M Davis wrote:
 ...You'd have to duplicate functions all over the place... - Jonathan 
 M Davis 

Can't you avoid that trivially with templates?

While templates can be used to coerce a lot of similar things together, it's rarely done without good cause. If you want to pass a short into a function accepting ints, you usually won't templatize the function. Probably more importantly, const getting added to D was a side effect of adding transitive immutability, and transitive immutability was a side effect of multithreading support. Head const and logical const do not exist in D because it was not required for multithreading. If Walter thought everyone would use templates to join mutable and immutable together, then const would not exist at all in D.
Sep 23 2011
prev sibling parent Mehrdad <wfunction hotmail.com> writes:
On 9/23/2011 11:33 AM, so wrote:
 On Fri, 23 Sep 2011 21:21:31 +0300, Mehrdad <wfunction hotmail.com> 
 wrote:

 Er, you answered a question about const with an answer about 
 immutable. :\

 My point is, what in the world does transitive const have to do with 
 transitive immutable?
 Can't you have immutable(T) be transitive while const(T) being 
 "normal", as in C/C++? If not, why not?

No you can't, i think you misunderstood the const in D. Without it immutable is close to worthless. You would have to implement every function for mutable and immutable.

Or just templatize it, like we've pretty much already been doing anyway...
Sep 23 2011
prev sibling next sibling parent so <so so.so> writes:
On Fri, 23 Sep 2011 21:21:31 +0300, Mehrdad <wfunction hotmail.com> wrote:

 Er, you answered a question about const with an answer about immutable.  
 :\

 My point is, what in the world does transitive const have to do with  
 transitive immutable?
 Can't you have immutable(T) be transitive while const(T) being "normal",  
 as in C/C++? If not, why not?

No you can't, i think you misunderstood the const in D. Without it immutable is close to worthless. You would have to implement every function for mutable and immutable.
Sep 23 2011
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, September 23, 2011 11:21 Mehrdad wrote:
 Er, you answered a question about const with an answer about immutable. :\

I gave more reasons than just immutability.
 My point is, what in the world does transitive const have to do with
 transitive immutable?
 Can't you have immutable(T) be transitive while const(T) being "normal",
 as in C/C++? If not, why not?

Anything which is const could actually be immutable. immutable(T) is implicitly convertible to const(T). It would be _incredibly_ limiting to immutable for it to be otherwise. You'd have to duplicate functions all over the place so that you had a const and an immutable version, and that results in a combinatorial explosion if you're dealing with multiple function parameters which could be either const or immutable. So, if you need transitive immutable, you need transitive const. - Jonathan M Davis
Sep 23 2011
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/22/2011 10:36 AM, Peter Alexander wrote:
 It's mostly for concurrent programming.

It's also for: 2. purity 3. support for true functional programming 4. implicit & enforcable documentation on what a function may do with its parameters 5. better isolation and encapsulation of specific areas in a program
Sep 24 2011
next sibling parent reply Peter Alexander <peter.alexander.au gmail.com> writes:
On 25/09/11 12:08 AM, Walter Bright wrote:
 On 9/22/2011 10:36 AM, Peter Alexander wrote:
 It's mostly for concurrent programming.

It's also for: 2. purity 3. support for true functional programming

Purity and (physical) immutability are separate concepts. Having immutable arguments is neither a necessary or sufficient condition for being pure. What do you mean by "true functional programming"? Just pure functional programming? As I explained in my 'Thoughts on Immutability in D' post, physical immutability is far too restrictive for functional programming, so I would say that immutable in D restricts true functional programming rather than supporting it. Supporting functional programming would mean supporting logical immutability, because that's all functional programs care about.
Sep 24 2011
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/24/2011 6:39 PM, Peter Alexander wrote:
 On 25/09/11 12:08 AM, Walter Bright wrote:
 3. support for true functional programming

Purity and (physical) immutability are separate concepts. Having immutable arguments is neither a necessary or sufficient condition for being pure. What do you mean by "true functional programming"? Just pure functional programming? As I explained in my 'Thoughts on Immutability in D' post, physical immutability is far too restrictive for functional programming, so I would say that immutable in D restricts true functional programming rather than supporting it. Supporting functional programming would mean supporting logical immutability, because that's all functional programs care about.

Functional programming means (in part) no side effects of functions, which means that global state cannot be modified through the parameters. Having the parameters be const/immutable is how this can be statically guaranteed.
Sep 24 2011
parent reply Peter Alexander <peter.alexander.au gmail.com> writes:
On 25/09/11 2:52 AM, Walter Bright wrote:
 On 9/24/2011 6:39 PM, Peter Alexander wrote:
 On 25/09/11 12:08 AM, Walter Bright wrote:
 3. support for true functional programming

Purity and (physical) immutability are separate concepts. Having immutable arguments is neither a necessary or sufficient condition for being pure. What do you mean by "true functional programming"? Just pure functional programming? As I explained in my 'Thoughts on Immutability in D' post, physical immutability is far too restrictive for functional programming, so I would say that immutable in D restricts true functional programming rather than supporting it. Supporting functional programming would mean supporting logical immutability, because that's all functional programs care about.

Functional programming means (in part) no side effects of functions, which means that global state cannot be modified through the parameters. Having the parameters be const/immutable is how this can be statically guaranteed.

It's easy to guarantee something. The difficult part is guaranteeing something without overly restricting it. You could just as easily get the same guarantee by disallowing references and forcing people to copy data across threads all the time. That would be a terrible. Likewise, getting the guarantee by forbidding equality preserving mutations is also terrible, although to a lesser extent.
Sep 24 2011
parent "dame" <damesureurnotme yousuck.gov> writes:
Peter Alexander wrote:

 It's easy to guarantee something.

Sep 24 2011
prev sibling parent reply Peter Alexander <peter.alexander.au gmail.com> writes:
On 25/09/11 12:29 AM, Jonathan M Davis wrote:
 On Saturday, September 24, 2011 16:08:04 Walter Bright wrote:
 On 9/22/2011 10:36 AM, Peter Alexander wrote:
 It's mostly for concurrent programming.

It's also for: 2. purity 3. support for true functional programming 4. implicit& enforcable documentation on what a function may do with its parameters 5. better isolation and encapsulation of specific areas in a program

I use it for _way_ more than concurrent programming. In fact, I use it pretty much the exact same what that I do in C++. The difference is that you can't do any kind of caching or lazy loading of member variables or member function return values, but I _rarely_ do that anyway, so for what I do, it isn't an impedement at all. I think that Peter's take on it stems from the fact that he's work in a gaming enviroment where he cares a lot more about stuff like lazy loading and caching, because he needs them for performance. I would say thought that most domains don't need that. Some obviously do, and it would be nice to have with const, but when you actually care about stuff like __restrict, you're in a _very_ different world from your average programmer.

Lazy loading isn't usually for performance. Lazy loading/evaluation has very different semantics to eager evaluation (see http://www.haskell.org/haskellwiki/Lazy_vs._non-strict). There are many non-performance uses for it. Same goes for caching. In any case, I'm all for catering to average users (whoever they are for D, most of the active users of D I see are game developers, or similar -- e.g. the PSPemu guy -- but maybe I have a skewed perspective), the problem I have is if the type system literally prevents me from expressing what I know to be valid code, with no legal escapes.
 The biggest roadblocks that I've run into with const stem from quality of
 implementation issues, which makes it so that const is unusable in a number of
 cases where it should be (e.g. this(this) not working with const and the fact
 that object isn't const-correct). So, I can't use it as much as I would like,
 but I use it a lot.

Heading off on a tangent here, but isn't the const this(this) problem a language problem rather than a QoI problem? Also, what's wrong with const-correctness on Object? All its methods are non-const as they should be. If you made, for example, toHash() const then you wouldn't be able to cache the hash, and that's *definitely* something people will want to do in many situations. Same goes for toString and opCmp/opEquals.
Sep 24 2011
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/24/11 9:07 PM, Peter Alexander wrote:
 Heading off on a tangent here, but isn't the const this(this) problem a
 language problem rather than a QoI problem?

The design exists but the implementation has not yet been finalized yet. Walter and I have taken the design to a conclusion at least two times, sigh.
 Also, what's wrong with const-correctness on Object? All its methods are
 non-const as they should be. If you made, for example, toHash() const
 then you wouldn't be able to cache the hash, and that's *definitely*
 something people will want to do in many situations. Same goes for
 toString and opCmp/opEquals.

All of these methods must have both const and non-const variants. The non-const variant forwards by default to the const one. Andrei
Sep 24 2011
parent Peter Alexander <peter.alexander.au gmail.com> writes:
On 25/09/11 3:51 AM, Andrei Alexandrescu wrote:
 On 9/24/11 9:07 PM, Peter Alexander wrote:
 Heading off on a tangent here, but isn't the const this(this) problem a
 language problem rather than a QoI problem?

The design exists but the implementation has not yet been finalized yet. Walter and I have taken the design to a conclusion at least two times, sigh.

That's good to hear. Any possibility of sharing what the design will be?
 Also, what's wrong with const-correctness on Object? All its methods are
 non-const as they should be. If you made, for example, toHash() const
 then you wouldn't be able to cache the hash, and that's *definitely*
 something people will want to do in many situations. Same goes for
 toString and opCmp/opEquals.

All of these methods must have both const and non-const variants. The non-const variant forwards by default to the const one.

I think that's a good choice. As long as const isn't forced for those operations.
Sep 25 2011
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 9/24/2011 7:31 PM, Jonathan M Davis wrote:
 Well I suppose that it's a matter of semantics, but it's _not_ valid code,
 because D's const is not a logical const and does not support logical const in
 any way.

I think that's the gist of it. Logical const is NOT CONST in D.
 The problem is the fact that there is no way in D to express the
 particular paradigm that you want to express - logical const.

There is: struct LogicalConst(T) { property T v() { if (!set) { _v = some_expensive_computation(); set = true; } return _v; } private: bool set = false; T _v; } Granted, that's a different way of doing it than C++ does it, but it is perfectly doable. It doesn't do anything dirty, unsafe, or underhanded. It isn't a fraud. It's even typesafe.
Sep 24 2011
parent reply bearophile <bearophileHUGS lycos.com> writes:
Walter:

 struct LogicalConst(T)
 {
       property T v() {
         if (!set) {
            _v = some_expensive_computation();
            set = true;
         }
         return _v;
      }
 
    private:
      bool set = false;
      T _v;
 }

If this idiom becomes common (thanks to its presence in D docs, etc) it is possible to add logic to the DMD front-end to recognize it (even when inlining of v() doesn't happen), and use this knowledge to perform some const-like optimizations. Is this possible and useful? Bye, bearophile
Sep 25 2011
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 09/25/2011 01:18 PM, bearophile wrote:
 Walter:

 struct LogicalConst(T)
 {
        property T v() {
          if (!set) {
             _v = some_expensive_computation();
             set = true;
          }
          return _v;
       }

     private:
       bool set = false;
       T _v;
 }

If this idiom becomes common (thanks to its presence in D docs, etc) it is possible to add logic to the DMD front-end to recognize it (even when inlining of v() doesn't happen), and use this knowledge to perform some const-like optimizations. Is this possible and useful? Bye, bearophile

I think it should be a language feature, as proposed by Jonathan.
Sep 25 2011
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Timon Gehr:

 I think it should be a language feature, as proposed by Jonathan.

I did miss his post. I see he has turn that idiom into a language feature :-) From Jonathan's post:
 2. __varLoaded is default-initialized to false, and __var is void (so,
garbage).

The GC has to read __varLoaded and then scan the contents of __var only if __varLoaded is true. To do this in user code (or code rewritten by front-end rules) time ago I have suggested to add this simple standard method to D: bool onGC(string fieldName)() {...} That if present is called by the GC during its scan, to know if a union/struct/clas method needs to be scanned now (I did invent it for unions, but it's useful for structs too, it seems). Bye, bearophile
Sep 25 2011
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, September 25, 2011 11:12:10 bearophile wrote:
 Timon Gehr:
 I think it should be a language feature, as proposed by Jonathan.

I did miss his post. I see he has turn that idiom into a language feature :-) From Jonathan's post:
 2. __varLoaded is default-initialized to false, and __var is void (so,
 garbage).

__varLoaded is true. To do this in user code (or code rewritten by front-end rules) time ago I have suggested to add this simple standard method to D: bool onGC(string fieldName)() {...} That if present is called by the GC during its scan, to know if a union/struct/clas method needs to be scanned now (I did invent it for unions, but it's useful for structs too, it seems).

Well, the big thing with my proposal is that it allows you to have lazy loading with the existing const. It doesn't attempt to introduce a new type of const or to solve the general issue of logical constness - just the lazy loading of a member variable which could have an expensive computation. - Jonathan M Davis
Sep 25 2011
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, September 24, 2011 16:08:04 Walter Bright wrote:
 On 9/22/2011 10:36 AM, Peter Alexander wrote:
 It's mostly for concurrent programming.

It's also for: 2. purity 3. support for true functional programming 4. implicit & enforcable documentation on what a function may do with its parameters 5. better isolation and encapsulation of specific areas in a program

I use it for _way_ more than concurrent programming. In fact, I use it pretty much the exact same what that I do in C++. The difference is that you can't do any kind of caching or lazy loading of member variables or member function return values, but I _rarely_ do that anyway, so for what I do, it isn't an impedement at all. I think that Peter's take on it stems from the fact that he's work in a gaming enviroment where he cares a lot more about stuff like lazy loading and caching, because he needs them for performance. I would say thought that most domains don't need that. Some obviously do, and it would be nice to have with const, but when you actually care about stuff like __restrict, you're in a _very_ different world from your average programmer. The biggest roadblocks that I've run into with const stem from quality of implementation issues, which makes it so that const is unusable in a number of cases where it should be (e.g. this(this) not working with const and the fact that object isn't const-correct). So, I can't use it as much as I would like, but I use it a lot. - Jonathan m Davis
Sep 24 2011
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, September 23, 2011 14:37 Mehrdad wrote:
 On 9/23/2011 11:47 AM, Jonathan M Davis wrote:
 ...You'd have to duplicate functions all over the place... - Jonathan
 M Davis

Can't you avoid that trivially with templates?

Then all of your functions have to be templated. Templated functions can't be virtual. And even if they _could_ be, that still requires that programmers template or duplicate functions all over the place. It not only increases the amount of bloat in the binary, but it creates more work for the programmer. Honestly, I don't understand what the problem with transitive const is. I see potential issues with the fact that it's not guaranteed to work to cast away const and alter the variable that was const. The lack of anything even similar to logical const _can_ be annoying. But the transitiveness of const? I really don't see any issue. It makes it easier for the compiler to make strong guarantees about type safety (especially when joined with the fact that casting away const and then mutating is undefined behavior), and it closes what I would consider enormous holes in C++'s const system. I would think that the fact that if you pass a variable to function which takes its arguments as const can _guarantee_ that that variable hasn't been altered after the call (assuming that there are no other references to it - or if the function is pure, assuming that you don't pass any other non-const references to that data to it) would be _very_ desirable. C++ can't guarantee anything of the sort, and if const in D weren't transitive, it couldn't make such guarantees either. What are you trying to do that the transitiveness of const causes issues? I just don't see the problem. - Jonathan M Davis
Sep 23 2011
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, September 23, 2011 15:27 Mehrdad wrote:
 On 9/23/2011 2:55 PM, Jonathan M Davis wrote:
 On Friday, September 23, 2011 14:37 Mehrdad wrote:
 On 9/23/2011 11:47 AM, Jonathan M Davis wrote:
 ...You'd have to duplicate functions all over the place... - Jonathan
 M Davis

Can't you avoid that trivially with templates?

Then all of your functions have to be templated.

Right... but we're already doing that with Phobos anyway...
 Templated functions can't be
 virtual. And even if they _could_ be, that still requires that
 programmers template or duplicate functions all over the place. It not
 only increases the amount of bloat in the binary, but it creates more
 work for the programmer.

... didn't I mention the same thing before, regarding too many templates in Phobos? I thought I always said functions shouldn't be templated, but everyone said it's OK because (1) that's how it is in C++, (2) it's faster, (3) etc., etc... I'm really confused by your [seemingly] contradictory reasoning. :\

There's plenty of stuff that's templated, but forcing you to template on const vs immutable would make the situation worse, and having const be intransitive while immutable is transitive could make creating such emplated functions problematic in some cases, because the semantics would be different. The really big problem though is that templated functions cannot be templated, so every class member function that needed to be overridable would have to be duplicated to handle both const and immutable. It's just _way_ simpler to make it so that both T and immutable(T) are implicitly convertible to const(T), and for that to work, const must be transitive. If we made it so that immutable(T) wasn't implicitly convertible to const(T), we'd be flooded with complaints about it - likely far more than we're seeing about const now.
 Honestly, I don't understand what the problem with transitive const is.
 What are you trying to do that the transitiveness of const causes issues?
 I just don't see the problem.
 
 - Jonathan M Davis

Wait, what? Haven't we already had enough complaints on the newsgroup about the problems with const? Are they all bogus or something?

The complaints have generally been about the lack of logical const and the inability to cast away const and modify variables _not_ about transitiveness. I'm not say that there have been _no_ complaints about the transitiveness about const, but I can't recall even _one_ issue with it at the moment. It's the lack of logical const that's generally complained about and has shown itself to be a major blocker for const in some cases. - Jonathan M Davis
Sep 23 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, September 23, 2011 18:52:23 Mehrdad wrote:
 On 9/23/2011 3:56 PM, Jonathan M Davis wrote:
 The complaints have generally been about the lack of logical const and
 the inability to cast away const and modify variables _not_ about
 transitiveness. I'm not say that there have been _no_ complaints about
 the transitiveness about const, but I can't recall even _one_ issue
 with it at the moment. It's the lack of logical const that's generally
 complained about and has shown itself to be a major blocker for const
 in some cases. - Jonathan M Davis

But the only reason logical const is an issue is indeed the fact that const is transitive. To illustrate, I run into problem almost every other time I use D, and to me it's *only* a problem because source is const: class MyRange : InputRange!char { char peeked; InputRange!char source; char front() const { // How do I lazy-load the value? if (peeked == '\0') { peeked = source.front; // ERROR, popFront isn't const... source.popFront(); } return peeked; } } If this isn't because of transitivity, then what is it? If only source wasn't implicitly const (and it wouldn't be in C++, since it'd be a const pointer to a non-const object) then this would be a piece of cake. I run into this problem and similar ones so often that it's driven me away from D, as much as I was a fan. If you have a nice solution then please let me know.

Then the lack of logical const is really your issue, not the transivity. Granted, logical const would be less of an issue if const weren't transitive, but ultimately, it's the fact that there is no way to alter a const variable without subverting the type system that's your problem. If you don't care about purity, it _is_ possible to have caching and lazy loading, but it's a bit ugly IMHO. If you have an AA outside of the object, you can cache the value you want in _it_. If the value isn't in the AA, then it still needs to be calculated, and if it _is_ in there, then you can just grab it from there. Voila, lazy loading and caching. But you lose purity, and it moves the data outside of the class itself (or at least out of the class instance - it could be a static variable in the class). So yeah, it kind of sucks, but it _is_ doable. So, is the fact that D's const does not allow for any kind of caching or lazy loading the only issue that you're really seeing with const (beyond implementation issues)? It _is_ an issue, and the transivity does make it worse, since more stuff is const than would be otherwise, but are there other issues beyond that? I think that it would be great if we could find a solution to lazy loading and caching so that it works with const, but I fear that at this point, that that is relegated to D3 unless someone can come up with a very clever solution that is backwards compatible. On the bright side though, it _does_ give us plenty of time to come up with a solid solution, since D3 won't be started for quite a while. But ultimately, it's a matter of tradeoffs. Do the benefits of transitive const outweigh the loss of caching and lazy loading? For most programs, I believe that the answer is definitely yes (especially since it helps enable immutable), but since it _is_ a tradeoff, it's definitely true that some programs will lose out on the ability to use const in places where it might be desirable. - Jonathan M Davis
Sep 23 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, September 23, 2011 19:58:41 Mehrdad wrote:
 On 9/23/2011 7:09 PM, Jonathan M Davis wrote:
 Then the lack of logical const is really your issue, not the
 transivity. Granted, logical const would be less of an issue if const
 weren't transitive, but ultimately, it's the fact that there is no way
 to alter a const variable without subverting the type system that's
 your problem.

Yeah, so we both seem to agree that the *cause* of the problem (inability to have logical const, or whatever you want to call it, I don't really care what it's called) is the presence of transitive const. I'm not talking about the problem, but the cause.
 If you don't care about purity, it _is_ possible to have caching and
 lazy loading, but it's a bit ugly IMHO.

Yeah, that's why I think we should remove the transitivity. Then this would be a non-issue.
 ...

No idea what you were saying since I don't know what "AA" stands for, sorry. :(

Associative array.
 So, is the fact that D's const does not allow for any kind of caching
 or lazy loading the only issue that you're really seeing with const
 (beyond implementation issues)?

Actually, it IS an implementation issue, not a performance/optimization issue. i.e. this class reads from a terminal, and it's not like I can make it read at a different time, since doing so at the wrong time would cause it to deadlock. So I have to grab the input on the first fetch, and it's not like I'm doing this to optimize anything... the code simply _won't function_ if I don't do this.
 It _is_ an issue, and the transivity does make it worse, since more
 stuff is const than would be otherwise, but are there other issues
 beyond that?

See above. It's a real issue, not a performance issue.
 I think that it would be great if we could find a solution to lazy
 loading and caching so that it works with const, but I fear that at
 this point, that that is relegated to D3 unless someone can come up
 with a very clever solution that is backwards compatible.

I guess that means D might not really catch on until D3? Problems like this come up often enough to make D kind of annoying to use...

Many, many people _never_ try and lazy load or cache variables like you're trying to do. So, there are many, many people that this will never affect. Obviously, it _will_ affect people but not enough that it would cripple D's chances of catching on. Also, since all you have to do to work around the issue is to not use const in this particular case (and there are already tons of programmers who never use const and have no interest in it), and you're fine, I don't see how this can be a showstopper for adopting the language. Yes, it's annoying, but there's a workaround which doesn't affect performance at all, and if something like this is all it takes for you to decide that you're not going to use a particular language, then it's going to be hard to get you to use _any_ language. They _all_ have issues of one sort or another, if nothing else because every language makes its own share of tradeoffs based on its goals. The question is whether the language as a whole meets your requirements enough better than another language, not whether one particular feature is a problem or not - though obviously a particular feature could be the straw that breaks the camel's back if there are a lot of issues. - Jonathan M Davis
Sep 23 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, September 23, 2011 22:24:37 Mehrdad wrote:
 Also, another problem I remembered about const:
 
 If you have a const object, you can't have an invariant() that calls
 something impure (or something like that -- I forget the details, it was
 a while ago). Which was pretty darn annoying when I was trying to use
 D's DBC features, which seemed to again conflict with the the
 transitivity of const.
 
 I'll post more issues as I remember them. There certainly wasn't just 1.
 
 See below for inline reply.
 
 -------------------
 
 On 9/23/2011 8:08 PM, Jonathan M Davis wrote:
 Many, many people _never_ try and lazy load or cache variables like
 you're trying to do. So, there are many, many people that this will
 never affect

Oh... was the purpose of D to appeal to /those/ kinds of people? If so, then please ignore this entire post; it was my mistake.

No. I'm saying that this particular issue is not an issue at all for many people. So, while this particular limitation of D's const may be annoying for some people, there are a _large_ number of D programmers that it will not impede at all, so for many programmers, it is not a showstopper issue at all. And for those where it _is_ a big issue, they have your choice of tradeoffs. Do they take the guarantees that D's const gives them and lose the ability to do lazy loading of member variables and caching of function return values in const objects, or do they not use const and lose the guarantees that it gives them but gain the ability to lazy load member variables and cache the return values of member functions? There are pros and cons to both choices. Making D's const intransitive provides an entirely different set of tradeoffs, and it was decided that based on D's design goals, transitive const was a better choice.
 Obviously, it _will_ affect people but not enough that it would
 cripple D's chances of catching on.

That's what we hope and keep our fingers crossed for, but something tells me that isn't quite enough. YMMV.
 Also, since all you have to do to work around the issue is to not use
 const in this particular case (and there are already tons of
 programmers who never use const and have no interest in it),and you're
 fine, I don't see how this can be a showstopper for adopting the
 language.

find this reasoning convincing, since I don't (and I don't think others do either).
 Yes, it's annoying, but there's a workaround which doesn't affect
 performance at all,

Was const introduced for performance, or for code verifiability? I don't see how that's relevant, because honestly, the word "performance" wasn't even in my /mind/ when I was thinking about this problem. All I wanted was to _compile_ *verifiably correct* code, which failed pretty darn miserably, due to the const issues. I couldn't care less about performance when I was writing my code.

I mention performance, because a wokaround that reduces performance is generally considered a negative and is unacceptable to many. In this case, the workaround reduces verifiability, which is also a negative (and which appears to be the reason why you don't like it). But the very thing that you're trying to do goes against the compiler's ability to verify code correctness with regards to const, and making const intransitive would seriously reduce the compiler's ability to verify correctness in many other cases. In either case, you don't really have any fewer guarantees than C++ gives you, because C++'s const doesn't really give you much in the way of guarantees. At best, it helps you catch bugs where you accidentally altered a variable which you intended to not alter (so you made it const). That's a benefit to having const in C++, but since mutable and casting away constness can completely circumvent const in C++, you really don't get any verifiable correctness out of the deal. So, D lost the ability to give the relatively small benefit of finding cases accidental mutation when using lazy loading and caching in a class or struct but gained the ability to give strong guarantees which absolutely guarantee that a const variable is not modified in any way unless you circumvent the type system.
 and if something like this is all it takes for you to decide that
 you're not going to use a particular language, then it's going to be
 hard to get you to use _any_ language.

I personally know that's not true, but why bother convincing you otherwise? Feel free to believe that, if it makes sense with your reasoning.
 They _all_ have issues of one sort or another, if nothing else because
 every language makes its own share of tradeoffs based on its goals.

NO! I think this is where you're missing the critical point. D's tradeoffs are NOT like other languages' tradeoffs. Widely-used languages (C++, Python, C#, whatever) do NOT have half-baked (or even 95%-baked) features. They have features that work 100% of the time. Sure, they may be incomplete and they certainly have more room for improvement, but _what they *already* have_ works in EVERY situation. If you ever wondered what people meant on programmers.se when they said "C++ has a better thought-out type system", I hope you now know why. They did NOT mean that it has better features. Or that the compilers are of better quality. They were saying that the rules are self-consistent and they *work*. That is, _regardless_ of the compiler quality, the features of the *language* itself work in EVERY situation. D, on the other hand, tries to appeal to everyone but instead has supposedly awesome features (e.g. transitive const) that DON'T work 100% of the time. They only work 95% of the time. You might refuse to believe this, but I'm convinced that this **IS** the reason why it's not being adopted as fast as you'd want it to be. You can continue to justify it as "but it works for 95% of people!" but the fact of the matter is that we've seen otherwise. Believe me, I want to see D get adopted too, but my brain is telling me that there HAS to be a reason it hasn't -- and that reason isn't the compiler bugs or anything of that sort, but the language itself.

_Every_ language has tradeoffs. A large number of the features in any language represent a tradeoff of some kind. I don't see why D's const is half-baked simply because it doesn't allow you to even fake logical const. I could just as easily argue that C++'s const is half-baked because it doesn't actually provide any real guarantee that a const value won't be changed. D's const works precisely as it was designed to work. It gives strong guarantees about const values not being altered - which includes disallowing anything akin to logical const. It trades the ability to have lazy loading and caching in a const object in favor of those strong guarantees, whereas C++ allows the lazy loading and caching at the cost of those strong guarantees. People complain all the time about features in other languages - especially C++. That does not make those languages (or D) half-baked or ill-thought out. In some cases, they have legitimate design mistakes. In others, it's a matter of tradefoffs and the fact that some design decisions in a language force other design decisions to go a certain way, even if that way may not be ideal. I can understand that you don't like the fact that D's const does not allow for lazy loading or caching in a const object, but that does not necessarily mean that D's const as it stands was a bad design decision or that it needs to be changed. I think that it would be wonderful if we could find a way to introduce lazy loading and caching to const objects in D, but I do _not_ think that doing so at the cost of the strong guarantees that transitive const provides is worth it. Obviously, you feel differently. It's a tradeoff, and you prefer one of two sides, whereas I prefer the other. - Jonathan M Davis
Sep 23 2011
prev sibling next sibling parent so <so so.so> writes:
On Sat, 24 Sep 2011 08:24:37 +0300, Mehrdad <wfunction hotmail.com> wrote:

 D, on the other hand, tries to appeal to everyone but instead has  
 supposedly awesome features (e.g. transitive const) that DON'T work 100%  
 of the time. They only work 95% of the time. You might refuse to believe  
 this, but I'm convinced that this **IS** the reason why it's not being  
 adopted as fast as you'd want it to be. You can continue to justify it  
 as "but it works for 95% of people!" but the fact of the matter is that  
 we've seen otherwise. Believe me, I want to see D get adopted too, but  
 my brain is telling me that there HAS to be a reason it hasn't -- and  
 that reason isn't the compiler bugs or anything of that sort, but the  
 language itself.

Everyone complaining about bugs, features not yet implemented, tool support, language transition but i have yet to see someone (if you ignore a few trolls) complain about the language itself. I don't understand what you are implying. I also don't understand why you are so overzealous on lconst. Caching, lazy binding and such are not immutable methods yet most people treat it like it was, thanks to the lconst. Its uselessness aside, do you imagine the consequences of adding yet another const system on top of a superior one? Are you really trying to improve the language or sabotage it :) Const systems be it logical or transitive are nothing but abominations, just look what have they done to C++, D. Now you want them both, no you got to pick one, and if i were you, i would pick transitive. Maybe it is you that should adopt the "new language" instead of what you are suggesting.
Sep 24 2011
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, September 25, 2011 03:07:22 Peter Alexander wrote:
 On 25/09/11 12:29 AM, Jonathan M Davis wrote:
 On Saturday, September 24, 2011 16:08:04 Walter Bright wrote:
 On 9/22/2011 10:36 AM, Peter Alexander wrote:
 It's mostly for concurrent programming.

It's also for: 2. purity 3. support for true functional programming 4. implicit& enforcable documentation on what a function may do with its parameters 5. better isolation and encapsulation of specific areas in a program

I use it for _way_ more than concurrent programming. In fact, I use it pretty much the exact same what that I do in C++. The difference is that you can't do any kind of caching or lazy loading of member variables or member function return values, but I _rarely_ do that anyway, so for what I do, it isn't an impedement at all. I think that Peter's take on it stems from the fact that he's work in a gaming enviroment where he cares a lot more about stuff like lazy loading and caching, because he needs them for performance. I would say thought that most domains don't need that. Some obviously do, and it would be nice to have with const, but when you actually care about stuff like __restrict, you're in a _very_ different world from your average programmer.

very different semantics to eager evaluation (see http://www.haskell.org/haskellwiki/Lazy_vs._non-strict). There are many non-performance uses for it. Same goes for caching. In any case, I'm all for catering to average users (whoever they are for D, most of the active users of D I see are game developers, or similar -- e.g. the PSPemu guy -- but maybe I have a skewed perspective), the problem I have is if the type system literally prevents me from expressing what I know to be valid code, with no legal escapes.

Well I suppose that it's a matter of semantics, but it's _not_ valid code, because D's const is not a logical const and does not support logical const in any way. So, the fact that you can't express valid code isn't really the issue, because you _can_ express valid code. What you want to do just isn't valid. The problem is the fact that there is no way in D to express the particular paradigm that you want to express - logical const.
 The biggest roadblocks that I've run into with const stem from quality
 of
 implementation issues, which makes it so that const is unusable in a
 number of cases where it should be (e.g. this(this) not working with
 const and the fact that object isn't const-correct). So, I can't use it
 as much as I would like, but I use it a lot.

Heading off on a tangent here, but isn't the const this(this) problem a language problem rather than a QoI problem?

Depends on how it's solved. I know that Andrei and Walter have a plan, but I don't know what it is. But if it's not a quality of implementation problem, then it's a quality of design problem, but regardless it's an issue that needs to (and will be) solved one way or another.
 Also, what's wrong with const-correctness on Object? All its methods are
 non-const as they should be. If you made, for example, toHash() const
 then you wouldn't be able to cache the hash, and that's *definitely*
 something people will want to do in many situations. Same goes for
 toString and opCmp/opEquals.

No. They are _supposed_ to be const, and they're going to be const. The fact that they aren't const is crippling to const. http://d.puremagic.com/issues/show_bug.cgi?id=1824 Now, once those functions are const, you should be able to override them with non-const versions, so as long as you're using a type which has a non-const version of the function you're trying to call, you should be able to have some level of caching and the like, but the fact those functions aren't const on Object is a big problem. It has been a long-standing complaint that those functions aren't const. And actually, we finally have pull requests which fix the problem, so there's a good chance that that bug will be fixed by the next release. - Jonathan M Davis
Sep 24 2011