Am I mistaken in saying that we are conflating:
   "anything that is logically const should be declared const"
   // makes perfect sense
// e.g. the lowest 2, and some branches of the 3rd and 4th, levels // of members (and a subset of the overall methods) in a 5-deep type hierarchy are const
   "most code/data should be declared const"
   // no! isn't efficient code all about mutation?
// no grounds for, e.g.: "ideally, no more than 40% of code should be doing mutation"

On Wednesday, 13 February 2019 at 16:40:18 UTC, H. S. Teoh wrote:
On Wed, Feb 13, 2019 at 11:32:46AM +0000, envoid via Digitalmars-d-learn wrote: Unfortunately, that guarantee also excludes a lot of otherwise useful idioms, like objects that cache data -- a const object cannot cache data because that means it's being mutated, or lazily-initialized objects -- because once the ctor has run, the object can no longer be mutated. Most notably, D's powerful range idiom is pretty much unusable with const because iteration over a range requires mutating the range (though having const *elements* in a range is fine). This doesn't seem as bad at first glance, but it wreaks havoc on generic code, another thing that D is purportedly good at. It's very hard (and often impossible) to write generic code that works with both const and mutable objects.

So ironically, the iron-clad semantics of D's const system turns out to be also its own downfall.


The point about generic code (reiterated by many) is intriguing on its own; until now, I hadn't explicitly thought about const even for my C++ template library code (whatever little I have of those). Any pointers to other posts or articles elaborating this a little bit?

I believe the other points probably matter when interacting with every other feature (I would have to write some of my "real" code in D to see if I hit it on my own), but there doesn't seem to be anything unusable about them on their own.

The inability to have a const caching object seems correct. The way around would be to have a wrapper that caches (meh). If that is not possible, then maybe caching objects just aren't meant to be const by their nature? Isn't memoize a standard library feature? I should look at it, but I wouldn't expect it to be const.

On Monday, 18 February 2019 at 06:50:32 UTC, Marco de Wild wrote:

I agree that const by nature unfortunately kills lazy initialization.

Lazy initialization - is this the same as post-blit? At the cost of copying (justifiable? maybe), doesn't D have a way to copy-construct a const/immutable struct object from a mutable one? If there is a way (or will be - there is a recent posting and a Dconf talk about copy constructors), does the copying negate the benefits of lazy initialization?

However, I don't really understand why const is a problem with ranges. Const elements are not a problem. Iterating over a range consumes it (if I understand correctly). It does not make sense to be able to consume a const object, so from my point of view it's perfectly logical to disallow iterating const ranges. If I'm missing something, please correct me.


Or I haven't understood why ranges would ever ever need to be const.
After all, in C++, what use is:
   std::vector::const_iterator const iter = sequence.begin();
About the only kind of use would be:
   std::vector::const_iterator iter = sequence.begin();
   std::vector::const_iterator const iterEnd = sequence.end();
What are ranges if not an encapsulation of the above functionality?

Reply via email to