www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.announce - Article: Why Const Sucks

reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
Here's something I wrote up on const:

http://jmdavisprog.com/articles/why-const-sucks.html

I suppose that it's not exactly the most positive article, but I feel that
it's accurate.

- Jonathan M Davis
Mar 05
next sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Monday, 5 March 2018 at 10:57:35 UTC, Jonathan M Davis wrote:
 Here's something I wrote up on const:

 http://jmdavisprog.com/articles/why-const-sucks.html

 I suppose that it's not exactly the most positive article, but 
 I feel that it's accurate.

 - Jonathan M Davis
My biggest issues with const are, as you wrote, ranges and postBlit. I still use `const` everywhere unless I can't. I used to use `immutable`, but gradually came around to only using it if I have to send data to another thread, otherwise it's too much of a hassle. Atila
Mar 05
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Monday, March 05, 2018 11:38:05 Atila Neves via Digitalmars-d-announce 
wrote:
 I used to use `immutable`, but gradually came around to only
 using it if I have to send data to another thread, otherwise it's
 too much of a hassle.
Aside from the whole std.concurrency situation, I generally use immutable in the places where the semantics are the same as const, so it doesn't generally cause a problem for me. I just prefer immutable in the cases where it and const are the same, because immutable clearly indicates that the value never changes, so immutable more closely fits the idea even if const happens to mean that in that particular case. I agree that using immutable where you have to do stuff like design objects in a particular way in order to make immutable work is generally too much of a pain to be worth it, but at least in those cases, the data can then be shared across threads, and it's data that doesn't need mutable backdoors, because it only makes sense to use immutable in that fashion when the object is really designed to never change state. I think that the only time that I've programmed heavily in a way that involves immutability everywhere is when I programmed in Haskell, and that combined with the fact that Haskell is lazy and completely functional such that you can't use imperative idioms anywhere made it so that each line of Haskell code took me more time to write than is the case with any other language I've used (except maybe batch, because of how insanely error-prone it is). I think that I'm a better programmer for it, but I'd hate to program that way normally, and using immutable all over the place would head too heavily in that direction - though at least D, unlike Haskell, is a multi-paradigm language and allows you to choose to use a particular idiom when you think it makes the most sense instead of forcing it everywhere. - Jonathan M Davis
Mar 05
parent Atila Neves <atila.neves gmail.com> writes:
On Monday, 5 March 2018 at 13:49:43 UTC, Jonathan M Davis wrote:
 On Monday, March 05, 2018 11:38:05 Atila Neves via 
 Digitalmars-d-announce wrote:
 I used to use `immutable`, but gradually came around to only 
 using it if I have to send data to another thread, otherwise 
 it's too much of a hassle.
Aside from the whole std.concurrency situation, I generally use immutable in the places where the semantics are the same as const, so it doesn't generally cause a problem for me. I just prefer immutable in the cases where it and const are the same, because immutable clearly indicates that the value never changes, so immutable more closely fits the idea even if const happens to mean that in that particular case. I agree that using immutable where you have to do stuff like design objects in a particular way in order to make immutable work is generally too much of a pain to be worth it, but at least in those cases, the data can then be shared across threads, and it's data that doesn't need mutable backdoors, because it only makes sense to use immutable in that fashion when the object is really designed to never change state. I think that the only time that I've programmed heavily in a way that involves immutability everywhere is when I programmed in Haskell, and that combined with the fact that Haskell is lazy and completely functional such that you can't use imperative idioms anywhere made it so that each line of Haskell code took me more time to write than is the case with any other language I've used (except maybe batch, because of how insanely error-prone it is). I think that I'm a better programmer for it, but I'd hate to program that way normally, and using immutable all over the place would head too heavily in that direction - though at least D, unlike Haskell, is a multi-paradigm language and allows you to choose to use a particular idiom when you think it makes the most sense instead of forcing it everywhere. - Jonathan M Davis
I prefer const over immutable because this compiles: string[] arr; const _ = arr; While this does not: string[] arr; immutable _ = arr; Basically, const just works and immutable is a hassle unless threads are involved. There are other situations where immutable is needed / should be preferred as well, notably: struct Foo { const(ubyte)[] bytes; } Construct Foo from a mutable buffer that you're reusing to get network traffic and you're going to have a bad time. Atila
Mar 05
prev sibling next sibling parent Dejan Lekic <dejan.lekic gmail.com> writes:
On Monday, 5 March 2018 at 10:57:35 UTC, Jonathan M Davis wrote:
 Here's something I wrote up on const:

 http://jmdavisprog.com/articles/why-const-sucks.html

 I suppose that it's not exactly the most positive article, but 
 I feel that it's accurate.

 - Jonathan M Davis
Brilliant article, Johathan! I feel the same...
Mar 05
prev sibling next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
Just a semantic note, it is "straitjacket". "straight" is like a 
non-wiggly line. "strait" means narrow or constricted. Thus, the 
straitjacket is a jacket that constricts your movement.

Of course, using "straight" is such a common mistake it has 
become generally accepted... but still, I like being precise with 
my words.
Mar 05
next sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Monday, March 05, 2018 13:48:23 Adam D. Ruppe via Digitalmars-d-announce 
wrote:
 Just a semantic note, it is "straitjacket". "straight" is like a
 non-wiggly line. "strait" means narrow or constricted. Thus, the
 straitjacket is a jacket that constricts your movement.

 Of course, using "straight" is such a common mistake it has
 become generally accepted... but still, I like being precise with
 my words.
Thanks for the correction. I probably knew at some point, but it's not a word that I use often, and I didn't even think about looking it up. Now, I'm more likely to remember in the future. - Jonathan M Davis
Mar 05
prev sibling next sibling parent Me <N/A yourmomsbed.com> writes:
  On Monday, 5 March 2018 at 13:48:23 UTC, Adam D. Ruppe wrote:
 Just a semantic note, it is "straitjacket". "straight" is like 
 a non-wiggly line. "strait" means narrow or constricted. Thus, 
 the straitjacket is a jacket that constricts your movement.

 Of course, using "straight" is such a common mistake it has 
 become generally accepted... but still, I like being precise 
 with my words.
You guys are a bunch of nerds . . . .
Mar 05
prev sibling next sibling parent Me <N/A yourmomsbed.com> writes:
On Monday, 5 March 2018 at 13:48:23 UTC, Adam D. Ruppe wrote:
 Just a semantic note, it is "straitjacket". "straight" is like 
 a non-wiggly line. "strait" means narrow or constricted. Thus, 
 the straitjacket is a jacket that constricts your movement.

 Of course, using "straight" is such a common mistake it has 
 become generally accepted... but still, I like being precise 
 with my words.
You guys are a bunch of nerds . . . . - Me
Mar 05
prev sibling parent Arun Chandrasekaran <aruncxy gmail.com> writes:
On Monday, 5 March 2018 at 13:48:23 UTC, Adam D. Ruppe wrote:
 Just a semantic note, it is "straitjacket". "straight" is like 
 a non-wiggly line. "strait" means narrow or constricted. Thus, 
 the straitjacket is a jacket that constricts your movement.

 Of course, using "straight" is such a common mistake it has 
 become generally accepted... but still, I like being precise 
 with my words.
Programmers like precision, don't we! From Simon Tatham article about how to report bugs effectively: https://www.chiark.greenend.org.uk/~sgtatham/bugs.html "Above all, *be precise*. Programmers like precision."
Mar 05
prev sibling next sibling parent reply SimonN <eiderdaus gmail.com> writes:
On Monday, 5 March 2018 at 10:57:35 UTC, Jonathan M Davis wrote:
 Here's something I wrote up on const:
Excellent read! I enjoyed the history of proposed solutions. I've run into the trouble with annotated opEquals in classes several times. I believe an empty/nonexistant Object class is the correct solution, together with templates. If it breaks tricky opEquals-overriding usercode, then so be it. The const trouble is merely a symptom here, the real problem is Object. In structs, all const members feel alien, they preventing all copying. This seems far harder to solve. -- Simon
Mar 05
parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Monday, March 05, 2018 13:53:21 SimonN via Digitalmars-d-announce wrote:
 On Monday, 5 March 2018 at 10:57:35 UTC, Jonathan M Davis wrote:
 Here's something I wrote up on const:
Excellent read! I enjoyed the history of proposed solutions. I've run into the trouble with annotated opEquals in classes several times. I believe an empty/nonexistant Object class is the correct solution, together with templates. If it breaks tricky opEquals-overriding usercode, then so be it. The const trouble is merely a symptom here, the real problem is Object.
Yes, the fact that those functions are on Object is a serious problem that affects more than const, but part of the reason for explaining that particular issue was to show how the use of const - or the lack thereof - on a member function can have serious consequences for a class hierarchy. It's by far the worst in the case of Object, because it affects _all_ classes in D, but any time that someone designs a class in D that is intendend to then have other classes derived from it, the same choices pop up; the consequences are just then on a smaller scale.
 In structs, all const members feel alien, they preventing all
 copying. This seems far harder to solve.
Yeah. I don't know what we do about that. In general, I think that it makes by far the most sense for value types to not be inherently const (even in part), so I'm not all that worried about the problems that stem from making a particular member variable const. But the fact that you then can't use a postblit constructor with a const object - even if nothing in the object is const unless the entire object is const - is definitely a problem. IIRC, Walter's take on it was that it was bad design for objects to deep-copy like that and that it was just better to use stuff like COW, in which case, postblit constructors aren't generally needed. And as such, he's a lot less worried about the problem than otherwise might be the case. I agree that it's frequently problematic for copying to be expensive in that manner, but it's also sometimes very useful. I expect that a good, solid DIP on the subject would be accepted in spite of the fact that Walter isn't big on postblit constructors, but first, someone has to come up with such a DIP, and that's not even vaguely easy - especially if the answer doesn't involve adding a copy constructor to the language (which I would guess would be rejected due the extra complexity that it would add to the language, but I don't know). Either way, right now, it's just one more thing on the list of things that makes it difficult enough to use const in D that many of us use it fairly minimally. - Jonathan M Davis
Mar 05
prev sibling next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Monday, 5 March 2018 at 10:57:35 UTC, Jonathan M Davis wrote:
 Here's something I wrote up on const:
So as to the main thrust, I generally agree. In fact, I think const is almost useless even if you want to use it fully: you said immutable is better in many places, and yes, but in addition to that, inout is better than const in most the remaining cases. Constructing a const variable? Almost completely useless - immutable is better in almost all (if not actually all) cases. Referencing function parameters? inout is better in all cases except just plain input. If there's any part of it being returned - as is the case on most member methods to me at least - inout is flat-out better. And then, of course, like you said "don't use it" is the solution to most of the const system's flaws anyway.... which seems to be the case with a lot of D's add-on qualifiers.
Mar 05
parent Guillaume Piolat <notthat email.com> writes:
On Monday, 5 March 2018 at 13:59:02 UTC, Adam D. Ruppe wrote:
 On Monday, 5 March 2018 at 10:57:35 UTC, Jonathan M Davis wrote:
 Here's something I wrote up on const:
And then, of course, like you said "don't use it" is the solution to most of the const system's flaws anyway.... which seems to be the case with a lot of D's add-on qualifiers.
+1 The worst part of those add-on qualifiers is that the official gospel is that they are useful when in reality you HAVE to avoid them to be productive.
Mar 06
prev sibling next sibling parent bauss <jj_1337 live.dk> writes:
On Monday, 5 March 2018 at 10:57:35 UTC, Jonathan M Davis wrote:
 Here's something I wrote up on const:

 http://jmdavisprog.com/articles/why-const-sucks.html

 I suppose that it's not exactly the most positive article, but 
 I feel that it's accurate.

 - Jonathan M Davis
Great read for a Monday.
Mar 05
prev sibling next sibling parent joe <joe example.com> writes:
On Monday, 5 March 2018 at 10:57:35 UTC, Jonathan M Davis wrote:
 Here's something I wrote up on const:

 http://jmdavisprog.com/articles/why-const-sucks.html

 I suppose that it's not exactly the most positive article, but 
 I feel that it's accurate.

 - Jonathan M Davis
Interesting read and it explains some of the incomprehensible error messages. Basically you're saying we've got a strong const in D but essentially the situation is much like in Java because the general approach is don't use it ? Kind of ironic. I made a Logger module a couple years back and I used const very generously. Then came the moment where the LogWriters actually had to do the writing. One would assume that a function called 'stdio.write' mutates some state, but it sure as hell doesn't affect the state of my logger. DMD said: So soooowy! writeln not const-y, no can do, soooowy! So I remove const. One function at a time and end up with a module where basically no const remains. But it doesn't stop there. Since logger isn't const anymore, it now can't be used in any const functions. So more de-const-ification happened... Also, it's frustrating to have to get rid of const because Object.toString uses some Outputwriter thing which is not const and therefore transitively you can't have const anywhere else. Kind of a disappointing experience. As far as I'm concerned, it's not so much "don't use const; or, it's not worth it" but more like "I would if I could but I can't so I shan't". I bother with const as much as possible but it's incredible frustrating and I would argue the time lost to de-const-ify APIs is easily equivalent to a code breaking change that would make const more applicable. Something possimpible. Like a compiler that doesn't purely make decisions upon a const keyword, but one that can understand that interacting with some random function with only "in" parameters or objects, which aren't even interacting with,or are part of, the object's internal state and are just passed through, can't violate the const-ness of the object. But there's likely much more to consider than that and I couldn't ever dream of implementing such a thing..unfortunately
Mar 05
prev sibling next sibling parent reply ShadoLight <ettienne.gilbert gmail.com> writes:
Very interesting and well written! Jonathan, your experiences 
with const in C++/Java just about matches my experiences with it. 
I also feel that the situation in D is less than ideal in this 
regard.

First, a small (for sure copy-pasta) typo in your article:

const(int[]) arr1 = getArray();
const(int)[] arr2 = p1;  //Sure you meant arr2 = arr1;

Regarding the proposed solution to the issues with Object namely 
"the solution to this problem which was agreed to a few years ago 
was to remove opEquals, opCmp, toHash, and toString from Object 
so that derived classes can define them with whatever attributes 
are desired" which, you say, will never happen because of too 
much code breakage...

What about the following? Currently the compiler is smart enough, 
so you can define class Foo and explicitly inherit from Object if 
you prefer:
class Foo : Object {..} //OK, no recursive Object inherits Object 
ad-infinitum.

Would it not be easier to exploit this and go the "opposite" way 
i.e. rather than remove it, just extend the hierarchy by adding a 
base class to Object itself (in object.d no less), something like 
this:

class ObjectBase
{
     interface Monitor{..}

     static ObjectBase factory(string classname){..}
}


class Object : ObjectBase
{
     string toString(){..}
     size_t toHash()  trusted nothrow{..}
     int opCmp(Object o){..}
     bool opEquals(Object o){..}

     static Object factory(string classname){..}
}

Now, if you do:

class Foo{..} //OK. Still inherits from Object i.e. identical to 
'class Foo : Object {..}
class Foo : Object {..} //The same, just explicit
//On the other hand:
class Bar : ObjectBase //Deliberately bypass inheritance from 
Object.

Inheritance from ObjectBase will have to be explicit (the price 
to pay for non-breakage!), but now class Bar is free to implement 
opEquals, opCmp, toHash, etc as it sees fit. This still 
guarantees back-wards compatibility since all classes currently 
inherited from Object have exactly the same semantics as they do 
today. No upgrades to any current projects/code required!

Why was something like this not considered (you don't give a 
link, so I cannot investigate), rather than simply removing them 
from Object? Can this be exploited to, in effect, create the same 
opportunity but minus the breakage? Or am I missing something?

Actually, in a more general sense I have begun to wonder if the 
common point of departure in D-land, that the concept of 
tail-const is actually a "part of" the concept of const, is not 
maybe wrong. We typically describe the concepts of 
tail/head-const "in terms of" const i.e. const in D 'equals' 
head-const 'plus' tail-const [1]. Since the concepts of 
tail-const and head-const are not that well known (outside of 
mostly C++-land), these 2 concepts are often utilized to 
differentiate D's concept of const, and explain it relative to 
the const (or final/sealed/readonly/etc) found in other 
languages. Maybe that muddles the water, and the 3 concepts, even 
though related, can semantically exist separately as well!

I am of the opinion that we really need something like tail-const 
in D - particularly to semantically mark that the "payload" in a 
range is constant, but that the range itself can mutate. But it 
invariably falls apart when you try to shoehorn it into the 
general concept of const-ness in D with its transitivity 
properties, etc. The 2 concepts just don't gel, and I think the 
only way this can be accomplished is to have a separate semantic 
construct and syntax for tail-const. I think the 2 use cases are 
mostly orthogonal, and only overlapping in a narrow sense - but 
it this narrow sense that is used to explain it!. And, yes, the 
tail-const version will have less guarantees and none of the 
optimization opportunities that the current const version can 
promise.

Of course I realize the changes of this being added to D is 
practically zero; So, yes, i have to concur with your conclusions 
as well!

PS. BTW, your blog's title "The Long-Winded D Guy" is quite 
brilliant. You are indeed a bit long-winded, but you also take 
the time to explain things very thoroughly. It is a trade-off and 
I think in your case the cost-benefit ratio is positive. Thank 
you for that! Also, if you ever write a book (it might have to 
come in multiple volumes ;-), you can already count on having 1 
buyer!

[1] https://dlang.org/articles/const-faq.html#const
Mar 05
parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Monday, March 05, 2018 17:35:28 ShadoLight via Digitalmars-d-announce 
wrote:
 Very interesting and well written! Jonathan, your experiences
 with const in C++/Java just about matches my experiences with it.
 I also feel that the situation in D is less than ideal in this
 regard.

 First, a small (for sure copy-pasta) typo in your article:

 const(int[]) arr1 = getArray();
 const(int)[] arr2 = p1;  //Sure you meant arr2 = arr1;
Thanks. Fixed.
 Regarding the proposed solution to the issues with Object namely
 "the solution to this problem which was agreed to a few years ago
 was to remove opEquals, opCmp, toHash, and toString from Object
 so that derived classes can define them with whatever attributes
 are desired" which, you say, will never happen because of too
 much code breakage...

 What about the following? Currently the compiler is smart enough,
 so you can define class Foo and explicitly inherit from Object if
 you prefer:
...
 Why was something like this not considered (you don't give a
 link, so I cannot investigate), rather than simply removing them
 from Object? Can this be exploited to, in effect, create the same
 opportunity but minus the breakage? Or am I missing something?
As I mentioned, there was recently some talk about creating a DIP to add a new root object below Object. If that's done, presumably, Object will still be the default to avoid code breakage, but it would be provide essentially what you're talking about. However, such a DIP still has to be written, so anything at this point is speculation as to what it's going to look like. At the time that it was decided to remove the functions from Object, it was more reasonable than it would be now (since D is definitely older now with a larger user base), and the details of how it would be done were never fully decided, which is part of why it's never come to fruition in spite of it being clear that we needed a root object without those functions. - Jonathan M Davis
Mar 05
prev sibling next sibling parent aberba <karabutaworld gmail.com> writes:
On Monday, 5 March 2018 at 10:57:35 UTC, Jonathan M Davis wrote:
 Here's something I wrote up on const:

 http://jmdavisprog.com/articles/why-const-sucks.html

 I suppose that it's not exactly the most positive article, but 
 I feel that it's accurate.

 - Jonathan M Davis
Its amazing how typed languages, in this case const, forces you to think in mutation but with an exception. I wonder the real world SOLE benefit of using const compared to mutable-immutable style. Its either mutable or immutable. Exception could only available by casting immutable to mutable. I feels this const thing is a theoretical problem. One can overcome practically with code style discipline. At a point, const becomes just a decoration; something people use prematurely (YAGNI). It must feel like sleeping on your bed with sharp knives hanging at the top such that they can fall on you anything: when comparing code in a typed language to an untyped one. That's a potential cause of premature use of certain type attributes. By the way, Jonathan, you should really consider writing a book with such deep insights your have. Especially the way you explain things.
Mar 06
prev sibling next sibling parent reply Radu <void null.pt> writes:
On Monday, 5 March 2018 at 10:57:35 UTC, Jonathan M Davis wrote:
 Here's something I wrote up on const:

 http://jmdavisprog.com/articles/why-const-sucks.html

 I suppose that it's not exactly the most positive article, but 
 I feel that it's accurate.

 - Jonathan M Davis
Spot on article, and touches some of my pain points when working with const/immutable structs. Recently I tried to create a ref-counted immutable struct, oh boi... This later use case is of tremendous value for safe concurrent code that's nogc. Unfortunately I couldn't find a way to make it work efficiently and in the same time not look like a disgusting hack. I suspect a possible solution is to allow immutable(const) postblit overloads as well as immutable dtors that will act as an escape hatch for unsafe work and in the same time provide hints that you are operating on an immutable(const) this.
Mar 06
parent Meta <jared771 gmail.com> writes:
On Tuesday, 6 March 2018 at 10:02:10 UTC, Radu wrote:
 On Monday, 5 March 2018 at 10:57:35 UTC, Jonathan M Davis wrote:
 Here's something I wrote up on const:

 http://jmdavisprog.com/articles/why-const-sucks.html

 I suppose that it's not exactly the most positive article, but 
 I feel that it's accurate.

 - Jonathan M Davis
Spot on article, and touches some of my pain points when working with const/immutable structs. Recently I tried to create a ref-counted immutable struct, oh boi... This later use case is of tremendous value for safe concurrent code that's nogc. Unfortunately I couldn't find a way to make it work efficiently and in the same time not look like a disgusting hack. I suspect a possible solution is to allow immutable(const) postblit overloads as well as immutable dtors that will act as an escape hatch for unsafe work and in the same time provide hints that you are operating on an immutable(const) this.
AFAIK this is a solved problem. Dicebot (not sure if he's still around) had initially proposed it: store the reference count just before the immutable piece of memory. | ref count | object/struct | In fact, Andrei added a new allocator to std.experimental.allocator to support this: https://dlang.org/library/std/experimental/allocator/building_blocks/affix_allocator/affix_allocator.prefix.html
Mar 06
prev sibling next sibling parent reply Dukc <ajieskola gmail.com> writes:
On Monday, 5 March 2018 at 10:57:35 UTC, Jonathan M Davis wrote 
(in the article):
 The problem is that the entire object must be fully initialized 
 before
 the body of the postblit constructor is run. That means that 
 any member
 variables which are const or immutable are stuck at whatever 
 they were in
 the original object, because it would violate the type system 
 to mutate them. And if an object is const or immutable, then 
 that's all of the members.
I think we have a misunderstanding here. According to that, this would not compile (imports left out): struct placeAtWorldMap { char[] title; int[2] coordsMicroDeg; this(this) { title = title.dup; } } void main() { char[] title = "London bridge".dup; const place = placeAtWorldMap(title, [51_508_038, -87_693]); const samePlace = place; "falling down ".copy(title); place.title.writeln; // falling down samePlace.title.writeln; // London bridge readln; } ...but it compiles and correctly runs, and I'm happy about that.
Mar 06
parent reply Nemanja Boric <4burgos gmail.com> writes:
On Tuesday, 6 March 2018 at 10:49:48 UTC, Dukc wrote:
 On Monday, 5 March 2018 at 10:57:35 UTC, Jonathan M Davis wrote 
 (in the article):
 The problem is that the entire object must be fully 
 initialized before
 the body of the postblit constructor is run. That means that 
 any member
 variables which are const or immutable are stuck at whatever 
 they were in
 the original object, because it would violate the type system 
 to mutate them. And if an object is const or immutable, then 
 that's all of the members.
I think we have a misunderstanding here. According to that, this would not compile (imports left out): struct placeAtWorldMap { char[] title; int[2] coordsMicroDeg; this(this) { title = title.dup; } } void main() { char[] title = "London bridge".dup; const place = placeAtWorldMap(title, [51_508_038, -87_693]); const samePlace = place; "falling down ".copy(title); place.title.writeln; // falling down samePlace.title.writeln; // London bridge readln; } ...but it compiles and correctly runs, and I'm happy about that.
Quote from the article:
 . That means that any member
 variables which are const or immutable are stuck at whatever 
 they were in
 the original object, because it would violate the type system 
 to mutate them
Meaning that if you declare your `title` member `const char[] title`, you can't change it in the postblit, but you could set it in the constructor. ``` import std.array; import std.stdio; import std.algorithm; struct placeAtWorldMap { const char[] title; int[2] coordsMicroDeg; this(char[] name) { this.title = name.idup; // you can assign const members here } this(char[] name, int[2] coords) { this.title = name; this.coordsMicroDeg = coords; } this(this) {// title = title.dup; // doesn't work anymore } } void main() { char[] title = "London bridge".dup; const place = placeAtWorldMap(title, [51_508_038, -87_693]); const newPlace = placeAtWorldMap("Big Ben".dup); const samePlace = place; "falling down ".copy(title); place.title.writeln; // falling down samePlace.title.writeln; // London bridge newPlace.title.writeln; // Big Ben } ```
Mar 06
parent reply Dukc <ajieskola gmail.com> writes:
On Tuesday, 6 March 2018 at 11:03:24 UTC, Nemanja Boric wrote:
     title = title.dup;    // doesn't work anymore
Strange! You're right it does not when the type declares a member as const, yet:
 On Monday, 5 March 2018 at 10:57:35 UTC, Jonathan M Davis 
 wrote (in the article):
 And if an object is const or immutable, then that's all of 
 the members.
...does not prevent the postblit from working whenthe object is declared const by user. I think we have a bug here. I believe postblits should behave like constructors in both events.
Mar 06
parent Dukc <ajieskola gmail.com> writes:
On Tuesday, 6 March 2018 at 12:05:26 UTC, Dukc wrote:
 I think we have a bug here. I believe postblits should behave 
 like constructors in both events.
https://issues.dlang.org/show_bug.cgi?id=18561
Mar 06
prev sibling parent reply joe <joe example.com> writes:
On Monday, 5 March 2018 at 10:57:35 UTC, Jonathan M Davis wrote:
 Here's something I wrote up on const:
 /snip
May be not entirely related, but a little gotcha. given: interface XY {} class Foo: XY {} class Bar: XY {} void doSomething(in XY sth) { auto foo = cast(Foo)sth; // error in safe code } But the compiler doesn't emit a warning that const got cast away in system code. Since system is the default setting and casting const away is by definition undefined behavior, there should be some feedback. If you cast away const in C++ you need to be explicit about it by using const_cast, documents the intention rather than D's swiss-army-cast.
Mar 08
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 3/8/18 9:58 AM, joe wrote:
 On Monday, 5 March 2018 at 10:57:35 UTC, Jonathan M Davis wrote:
 Here's something I wrote up on const:
 /snip
May be not entirely related, but a little gotcha. given: interface XY {} class Foo: XY {} class Bar: XY {} void doSomething(in XY sth) {   auto foo = cast(Foo)sth; // error in safe code } But the compiler doesn't emit a warning that const got cast away in system code. Since system is the default setting and casting const away is by definition undefined behavior, there should be some feedback. If you cast away const in C++ you need to be explicit about it by using const_cast, documents the intention rather than D's swiss-army-cast.
This is a problem with the cast system, not const. D has one cast mechanism, and it's used to: a) dynamic type cast b) hook user-supplied opCast c) enter undefined behavior by casting away const/immutable. I really think we should have a separate mechanism for a and b, as they are far less dangerous than c. std.conv.to does this as well, but the language should have some safeguards against using "safe casting" incorrectly. -Steve
Mar 08
parent joe <joe example.com> writes:
On Thursday, 8 March 2018 at 15:13:09 UTC, Steven Schveighoffer 
wrote:
 On 3/8/18 9:58 AM, joe wrote:
 On Monday, 5 March 2018 at 10:57:35 UTC, Jonathan M Davis 
 wrote:
 Here's something I wrote up on const:
 /snip
May be not entirely related, but a little gotcha. given: interface XY {} class Foo: XY {} class Bar: XY {} void doSomething(in XY sth) {   auto foo = cast(Foo)sth; // error in safe code } But the compiler doesn't emit a warning that const got cast away in system code. Since system is the default setting and casting const away is by definition undefined behavior, there should be some feedback. If you cast away const in C++ you need to be explicit about it by using const_cast, documents the intention rather than D's swiss-army-cast.
This is a problem with the cast system, not const. ...
I figured. Sorry for off topic.
 ... D has one cast mechanism, and it's used to:

 a) dynamic type cast
 b) hook user-supplied opCast
 c) enter undefined behavior by casting away const/immutable.

 I really think we should have a separate mechanism for a and b, 
 as they are far less dangerous than c.

 std.conv.to does this as well, ...
Thanks for pointing this out.
 ...but the language should have some safeguards against using 
 "safe casting" incorrectly.

 -Steve
yes, that's what I was aiming for :) This one got me because I assumed, with all the improved security in place, D would never silently do such a thing... Assumptions, right? ...the root of all evil. I should know better. haha. Anyways, thanks for the insight and have a nice Sunday.
Mar 11