On Sunday, March 26, 2017 18:31:52 Jerry via Digitalmars-d wrote: > On Sunday, 26 March 2017 at 15:29:02 UTC, Jonathan M Davis wrote: > > Personally, I don't think that the fact that you can't use > > const for head-const in D is really a loss, since it's almost > > never what you want. Tail-const is _way_ more useful. But it is > > true that by making D's const fully transitive, there are > > variations of constness that C++ can do that D can't. immutable > > pretty much forces that though, and it does simplify the > > language. > > There are quite a few things wrong with const, it's so bad phobos > isn't even const-correct when it should be. In cmp() for example, > if you pass a lambda that takes the parameters by reference. You > will be modifying temporary values that cmp() created on the > stack. These should be const, but then what if it is a pointer? > It is a different situation and you don't really want const cause > you are going to be modifying the correct struct (the one pointed > to). It is just easier to not use const in D cause it makes your > code more difficult to actually use. That's exactly what Phobos > does, it ignores const for the most part because it is easier not > to use it.
There are significant pros and cons when comparing C++ and D's const, but they usually relate to the ability to get around const in C++ and the lack of ability to do so in D. The ability to create a const pointer to a mutable element is occasionally something that someone wants to do, but in my experience, it's pretty useless. I'm not sure that I've ever used it in C++ (and I've programmed professinally primarily in C++), and when I was learning Java and found out that that's what Java's final did, I decided that all it was good for was constants of built-in types, and I think that that's mostly what I've seen other folks do with it. Having a pointer/reference that can't change while what it points to can just isn't very useful. It's having a mutable pointer to const that's useful. Now, as for const in D in general and how it compares to C++, that's a rather difficult question and highly debatable (and it's been debated here on many occasions). C++'s const is little more than documentation. It prevents accidental mutation, but there are so many ways around it that it's borderline meaningless. It only works as well as it does, because it's a convention that programmers _usually_ hold to. But it gurantees almost nothing. For instance, it's perfectly possible to have a class where all of its members are const but where all of them mutate the state of the object. The fact that that doesn't normally happen is simply because fortunately, programmers normally choose to behave themselves with mutable and casting away const. But they don't have to, and the compiler doesn't enforce it. D's const, on the other hand, has strong guarantees about something that's const never being mutated unless something elsewhere in the code has access to a mutable reference and changes the data that way. The const reference is never able to change the data without violating the type system. So, D's const actually means something. It provides real guarantees. But the reality of the matter is that that's so restrictive that pretty quickly you simply can't use const. There are too many idioms that require backdoors to const - mutexes, memory management, lazy initializaiton, etc. So, the end result is that in C++, you don't have much in the way of guarantees, but you're able to use what you do have all over the place. Accidental mutation is prevented and programmer intention is conveyed, but not much of anything is really guaranteed. Whereas with D, you have the strong guarantees, and you can use const in certain circumstances, but you're quickly forced to use it in only very restricted circumstances - especially if user-defined types or templates are involved. Too much simply doesn't work with true const. What most code really needs is logical const, and the compiler can't guarantee that. As to whether C++ or D did a better job with const, I really don't know. I find C++'s const to be pretty terrible from the standpoint of what it really protects, and I only recall one time in my entire programming career that it's actually caught a bug for me, but it's still nice to be able to indicate that a function doesn't mutate its arguments, even if it's not actually guaranteed, since it's usually true. The fact that D's const provides the stronger guarantees is fantastic, but it's also so restrictive that it borders on useless. So, ultimately, I'm not very happy with either solution, and I don't know what the best one would be. Arguably, immutable is what's truly useful - though obviously, code has to be written with it in mind, because a lot of code won't work with it without that - but for it to do its job, D's const pretty much has to be the way it is. Even if we wanted C++'s const in D, we couldn't have it unless it didn't interoperate with immutable. And as for the C++ concept of "const-correctness", I think that the end result of all of this is that it really doesn't apply to D. When code is const-correct, that essentially means that it will compile with const and that it's theoretically, "logically" const - _not_ that it's actually const. It's about convention and conveying the intention of the programmer, not actually guaranteeing anything. And D's const is all about guarantees. For better or worse, I think anyone thinking about const-correctness with D code is almost certainly thinking about const the wrong way in D. And yes, the end result of all of this is that templated code can almost never use const. So, a _lot_ of Phobos doesn't use it. And on some level, that sucks, but I'm not sure that we'd really be any better off with C++'s const either. There are pros and cons both ways. - Jonathan M Davis