digitalmars.D - any news on const/invariant?
- Denton Cockburn (3/3) Nov 26 2007 Any update on the status of the const/invariant changes?
- Walter Bright (4/7) Nov 26 2007 While the semantic changes are extensive, I've found to my surprise that...
- Jason House (2/12) Nov 26 2007
- Walter Bright (6/15) Nov 26 2007 I don't remember the details of that, but the nutshell version is:
- Jason House (8/20) Nov 26 2007 Sounds about the same... I remember it as "transitive const".
- Derek Parnell (17/34) Nov 26 2007 Does that mean that if X is const then neither the bits in X and the bit...
- Walter Bright (11/42) Nov 26 2007 Const and invariant are transitive. C++ const is not transitive, leading...
- Steven Schveighoffer (13/22) Nov 26 2007 Before, I could declare an array of const characters. Essentially, the
- Walter Bright (6/32) Nov 26 2007 A "fully const array" would be declared as:
- Derek Parnell (18/48) Nov 26 2007 And I assume that 'transitive' in this context means that if X is const
- Walter Bright (6/44) Nov 26 2007 No. "const char[] X;" and "const(char[]) X;" mean the same thing.
- Derek Parnell (17/22) Nov 26 2007 I am under the impression that this is a fairly common way of doing thin...
- 0ffh (3/9) Nov 26 2007 void GammaAdjust(ref byte[] bitmap,float gamma) ?
- Bill Baxter (10/20) Nov 26 2007 byte[] bitmap;
- 0ffh (1/1) Nov 26 2007 Dr. Egon Spengler: Don't cross the streams. =)
- Walter Bright (3/25) Nov 26 2007 I'm not sure why one would need protection against changing the bitmap
- Derek Parnell (15/17) Nov 26 2007 byte[] bitmap;
- Janice Caron (5/14) Nov 26 2007 The GammaAdjust routine /cannot/ change the pointer, because it is
- Nathan Reed (8/10) Nov 26 2007 One which, I would think, should be caught by the type system. However,...
- Derek Parnell (11/22) Nov 26 2007 I'm talking about having the compiler help catch coding mistakes at comp...
- Bill Baxter (15/33) Nov 27 2007 If you're worried about the implementer doing the wrong thing then you
- Walter Bright (6/10) Nov 27 2007 It is clear that the previous implementation of const, while it allowed
- Derek Parnell (13/32) Nov 26 2007 I'm sorry I'm not getting my request out clear enough.
- Walter Bright (3/19) Nov 27 2007 Change GammaAdjust from (ref byte[] bitmap) to (byte[] bitmap), and it
- Steven Schveighoffer (38/50) Nov 27 2007 I think you are missing something here. Let's view this as it really is...
- Derek Parnell (17/50) Nov 27 2007 Arrrgh!
- Steven Schveighoffer (6/45) Nov 27 2007 I understood what you meant. My point is that the compiler cannot preve...
- Derek Parnell (7/11) Nov 27 2007 Thank you.
- Derek Parnell (9/27) Nov 26 2007 Okay, I get it. We don't actually need const/invariant at all. Instead w...
- Tomas Lindquist Olsen (7/12) Nov 26 2007 I think this new const sounds like a reasonable compromise to get simple...
- Derek Parnell (19/33) Nov 26 2007 I agree that the const as now proposed is simple and still useful. I'm
- Walter Bright (8/14) Nov 27 2007 Head const turned out to be an unexplainable, incomprehensible feature.
- 0ffh (9/19) Nov 27 2007 I think you forget (or ignore) something elemental here, which is that
- Derek Parnell (25/48) Nov 27 2007 Neither did I forget nor ignore. My 'assert' comment was a (poor) exampl...
- 0ffh (23/42) Nov 27 2007 Neither am I. But I've lived a reasonably long life coding without "cons...
- Rioshin an'Harthen (28/42) Nov 28 2007 I believe head const is a feature that should exist. I'm just a bit unsu...
- Walter Bright (10/14) Nov 28 2007 The only person I know of who understood it was Andrei. This is despite
- Derek Parnell (12/16) Nov 28 2007 I though it was simply "the pointer can't change but what it points to
- Steven Schveighoffer (13/15) Nov 28 2007 const const(int)* f(){ ... }
- Walter Bright (4/21) Nov 28 2007 A const function returning an int*. The const here is just redundant.
- Bruce Adams (9/13) Nov 29 2007 What would be the point of an invariant method? A const method promises ...
- Janice Caron (17/22) Nov 29 2007 It makes a difference. Watch...
- Janice Caron (32/32) Nov 29 2007 Hope yall were paying attention and spotted that I screwed that up
- Bill Baxter (14/32) Nov 28 2007 Currently:
- Sean Kelly (8/26) Nov 29 2007 My issue with the design wasn't so much with the conceptual complexity
- Georg Wrede (9/26) Dec 17 2007 I do.
- Bill Baxter (13/17) Nov 26 2007 I pass you a buffer that I've carefully pre-allocated for you to fill
- 0ffh (4/20) Nov 26 2007 Okay, that's a feature.
- Bill Baxter (4/25) Nov 26 2007 More wordy and not checked at compile time.
- Walter Bright (2/11) Nov 26 2007 Then just pass in the buffer[]. No need to pass *buffer* by reference.
- Regan Heath (15/28) Nov 27 2007 void foo(char[] pbuffer)
- Walter Bright (2/17) Nov 27 2007 No. foo() modifies its copy of pbuffer, which is not the same as buffer.
- Regan Heath (4/22) Nov 27 2007 Yes, but the underlying memory is reallocated so buffer no longer points...
- Frank Benoit (5/29) Nov 27 2007 You missed a semicolon, so it does not compile :)
- Regan Heath (20/48) Nov 27 2007 'realloc' (the ANSI C version) free's the original buffer.
- Regan Heath (26/29) Nov 27 2007 Seems like you were right about this. This seems to be the code in
- Leandro Lucarella (16/46) Nov 27 2007 I think you are missing an important point here: string concatenation is...
- Christopher Wright (3/42) Nov 27 2007 Though in the calling method, the buffer length wouldn't change, so if
- Regan Heath (43/77) Nov 27 2007 In fact I missed it too!
- Steven Schveighoffer (6/47) Nov 27 2007 It is very deterministic actually. From
- Regan Heath (10/56) Nov 27 2007 True, but the example after that statement is:
- Walter Bright (2/24) Nov 27 2007 No, a new copy is made. The old one is left alone.
- Sean Kelly (3/21) Nov 27 2007 So we'll have pass by value for arrays? Nifty.
- Walter Bright (3/24) Nov 27 2007 Arrgh! There are two things here, the length/ptr, and the array
- Sean Kelly (5/30) Nov 27 2007 Oops! I totally misunderstood. This is yet another reminder of why I
- 0ffh (5/11) Nov 26 2007 Well, it might make sense with a moving GC, I suppose;
- Robert Fraser (2/54) Nov 26 2007 I like it! Simple, yet it does what it needs to do.
- James Dennett (9/12) Dec 17 2007 How about a constant/immutable object that refers to and
- Bill Baxter (4/16) Dec 17 2007 But the compiler needs to assume that every reference could be an owned
- Jason House (3/19) Dec 17 2007 Is it really about ownership? That tends to imply to me that this would...
- James Dennett (18/43) Dec 17 2007 More about "containment", but that implies ownership, and D
- Victor Tyurin (7/17) Nov 26 2007 Walter, please, explain us, why you don't post any thoughts on important
- Denton Cockburn (7/25) Nov 26 2007 On Mon, 26 Nov 2007 23:43:21 +0300, Victor Tyurin wrote:
- Derek Parnell (10/14) Nov 26 2007 Prior to releasing the new version, will you tell us what the semantic
- Bill Baxter (8/12) Nov 26 2007 You can get a preview of the new way things are going to look by
- Walter Bright (3/16) Nov 26 2007 At the beginning will still work for function types. The at the end
- Extrawurst (1/17) Nov 26 2007
- Extrawurst (5/21) Nov 26 2007 honestly i would prefer just one single way of writing things. allowing
- Michel Fortin (13/25) Nov 27 2007 I second that: the language should help make code consistent. I don't
- Bill Baxter (4/29) Nov 27 2007 I agree. I don't get why we need two ways to express it. What's the
- Walter Bright (10/12) Nov 27 2007 1. It's semantically consistent.
- Janice Caron (3/13) Nov 27 2007 Oh, well if you put it like that, I have to agree with you! :-)
- Chris Miller (12/20) Nov 27 2007 The above could be the same as:
- Janice Caron (4/7) Nov 27 2007 It's what I would assume too. That's what the "principle of least
- Walter Bright (8/13) Nov 27 2007 Think about const as applying to the item being declared. Here, foo is
- Bill Baxter (35/53) Nov 27 2007 But const on a function isn't really a storage class. It's a type
- Daniel Keep (64/129) Nov 27 2007 Only because you say it is. Pretend we don't have the current C-style
- Bill Baxter (36/104) Nov 27 2007 Maybe I'm missing something here, but what exactly are you thinking
- Daniel Keep (28/121) Nov 27 2007 No, you're not missing anything. Personally, I blame brain-slippage.
- Walter Bright (3/8) Nov 27 2007 That's right, too.
- Janice Caron (39/47) Nov 27 2007 I think we do all understand this. The problem is that it took us
- Walter Bright (6/15) Nov 28 2007 I think it would be pretty hard to give up:
- Janice Caron (17/22) Nov 28 2007 Why? It would just turn into something else, like
- Walter Bright (12/40) Nov 28 2007 Because those alternatives all look terrible. And frankly, how could
- Bill Baxter (24/43) Nov 28 2007 We're talking here about methods, right? And you're saying if we can do...
- Janice Caron (11/14) Nov 28 2007 Put like that, it does make sense.
- Walter Bright (15/39) Nov 28 2007 Ok, let's assume C++ is intuitive, consistent, and logical. Given:
- Bill Baxter (21/73) Nov 28 2007 Ok, but that seems to differ from your default position on other topics....
- Walter Bright (4/16) Nov 28 2007 No, because to break things in a way that results in an error message is...
- 0ffh (5/6) Nov 28 2007 Having second thoughts, I suppose that some people might
- Bill Baxter (14/32) Nov 28 2007 Doesn't
- Sean Kelly (3/7) Nov 28 2007 It's still there. Check phobos/internal/object.d :-)
- Walter Bright (3/24) Nov 28 2007 The C way is still supported.
- Jarrett Billingsley (4/5) Nov 29 2007 As is uglily demonstrated by DDoc and all compiler error messages involv...
- Janice Caron (5/11) Nov 28 2007 You are of course completely correct about that, Walter. However,
- Walter Bright (8/13) Nov 28 2007 But much of the justifications used here are that C++ is intuitive. It
- James Dennett (6/15) Dec 17 2007 I don't think it's that C++ is intuitive: it's that it's not as
- 0ffh (13/34) Nov 28 2007 Okay, you can take me as one sample, I suck at C++! Hah!
- Walter Bright (6/9) Nov 28 2007 For new code, there isn't much point to using the C style array
- Ary Borenszweig (7/19) Nov 28 2007 But it could be automated with a smarter "editor". In fact, I'm willing
- Clay Smith (2/14) Nov 28 2007 I agree, it is useful to help port C/C++ code to D.
- Janice Caron (70/81) Nov 28 2007 You have misunderstood me. The suggestion is that "const" shall not be
- Bill Baxter (10/74) Nov 28 2007 Janice, what are your thoughts about how the 'static' attribute fits
- Janice Caron (20/28) Nov 28 2007 I have to agree with you.
- Derek Parnell (21/26) Nov 28 2007 The simple fact is that
- Walter Bright (19/34) Nov 28 2007 The rule for constructing a const type is to enclose that type in
- Bill Baxter (6/44) Nov 28 2007 That's a good way to remember it. If we get used to seeing and writing...
- Walter Bright (17/97) Nov 28 2007 The C++ spec doesn't call const a storage class explicitly, but it is
- Janice Caron (12/19) Nov 28 2007 It adds the ability to parse the declaration differently, so that
- Walter Bright (4/11) Nov 28 2007 No. Storage class are not type constructors. To use const as a type
- Bill Baxter (22/37) Nov 28 2007 Here's a class that compiles fine and will probably mostly work.
- Walter Bright (3/33) Nov 28 2007 Yes. So where's the problem? Also, why would one want to return a "const...
- Bill Baxter (6/26) Nov 28 2007 Doh. Good point. It doesn't make much sense returning a const int.
- Bruce Adams (27/52) Nov 29 2007 =
- Bill Baxter (21/74) Nov 29 2007 Oh, yeh, I do vaguely remember that one. Good point.
- Bill Baxter (6/64) Nov 29 2007 My bad, the compiler actually catches that. But it doesn't catch it if
- Janice Caron (19/24) Nov 30 2007 Of course it's not consistent with existing syntax, otherwise it would
- James Dennett (15/32) Dec 17 2007 A good compiler can do that for you too (though using lint
- Bill Baxter (10/47) Dec 17 2007 I can't speak for all the cases the original poster was talking about,
- Oskar Linde (12/23) Dec 17 2007 Isn't there a value in knowing the argument will never change when
- Bill Baxter (7/33) Dec 17 2007 If the compiler can verify that no attempts were made to modify the
- James Dennett (6/41) Dec 18 2007 Separate compilation means that the compiler can verify clients
- James Dennett (10/61) Dec 18 2007 And you're close to the crucial point. For C++, it makes sense to
- Bruce Adams (45/78) Dec 17 2007 In actual fact when I sat down to check it and prove the point either wa...
- Bruce Adams (10/31) Dec 17 2007 =
- Dan (5/32) Dec 17 2007 What if I want to pass a struct by value without copying - because I onl...
- Bruce Adams (7/16) Dec 17 2007 I can imagine how to do that in assembly. Its not possible in C/C++
- Oskar Linde (14/18) Nov 28 2007 Honestly, I am confused about what that means. If I define an integer
- Sean Kelly (6/13) Nov 28 2007 I can't stand the use of "invariant" as a qualifier either, but what can...
- Walter Bright (9/30) Nov 28 2007 For a basic type, the meaning of const and invariant overlap. The
- Oskar Linde (33/65) Nov 29 2007 Ok, but it is then unfortunate that having two constants:
- Walter Bright (12/27) Nov 29 2007 It's not that bad. Consider:
- Oskar Linde (56/86) Nov 29 2007 Oh, really? ;p. I don't think that is much of an argument. Think of the
- Janice Caron (66/66) Nov 29 2007 Yes, Oskar is right in his analysis of const vs invariant
- Regan Heath (9/30) Nov 29 2007 I think I'd rather loose:
- Janice Caron (5/7) Nov 29 2007 But if you did that, you wouldn't be able to declare const member
- Sean Kelly (5/16) Nov 29 2007 This is one reason I think "const" should be used for "data that will
- Walter Bright (16/16) Nov 29 2007 Invariant member functions: you argued these are unnecessary. I believe
- Steven Schveighoffer (11/16) Nov 29 2007 I believe pure functions are required to support functional programming ...
- Janice Caron (31/38) Nov 30 2007 Actually is does. If you followed all the details of my previous post,
- Kenny TM~ (9/24) Nov 29 2007 No, please, no. This breaks too many codes, and makes
- Bill Baxter (21/36) Nov 29 2007 FWIW my naive expectation was that "invariant a = 1" would give you
- Oskar Linde (8/23) Nov 29 2007 For function signatures, the "in" parameter attribute should save some
- Bruce Adams (17/24) Nov 29 2007 compilers are used to write firmware which gets downloaded into EEPROMs ...
- Russell Lewis (3/6) Nov 30 2007 You can always put these variables into virtual pages which are
- Sean Kelly (4/13) Nov 29 2007 I favor "view" but I suppose it's too common a word. "guard" seems
- Bruce Adams (68/94) Nov 29 2007 =
- Steven Schveighoffer (25/39) Nov 28 2007 Let me reword Walter's point, as I think he didn't really get it across
- Derek Parnell (16/23) Nov 28 2007 Got it. When I see two adjacent "const" keywords I need to realize that ...
- Steven Schveighoffer (8/31) Nov 28 2007 Hey, I'm not saying it's the best way :) I'm just saying it's no less o...
- Walter Bright (7/21) Nov 28 2007 To make a type const, you add parens:
- Derek Parnell (13/20) Nov 28 2007 Is this supposed to compile? I can't get it to work.
- Walter Bright (2/13) Nov 29 2007 Uh, you're right. You can't put the identifier inside a declarator.
- Derek Parnell (9/22) Nov 29 2007 Yes, I know one can't, but I actually asked if one is supposed to able t...
- Walter Bright (2/4) Nov 29 2007 No. I just didn't think it through.
- Leandro Lucarella (17/64) Nov 29 2007 This is what it's confusing.
- Walter Bright (3/5) Nov 29 2007 No, const Type X always means const(Type) x, where Type is the type of
- Oskar Linde (10/28) Nov 28 2007 Shouldn't const as a storage class mean really constant, so that
- Janice Caron (15/20) Nov 28 2007 Actually, I may have been misunderstood, so I want to be clear. There
- Sean Kelly (3/26) Nov 28 2007 Um, "const x = 3" *is* legal in D. Has been for about a year now.
- Janice Caron (6/8) Nov 28 2007 No need for the "Um". Of course I know that, and certainly I should
- Sean Kelly (4/14) Nov 28 2007 I disagree. But back to the main point. You claimed that D does not
- Janice Caron (16/18) Nov 28 2007 Certainly. In the grammar of C and C++, a rule is defined called
- Walter Bright (5/27) Nov 28 2007 I think this is a distinction without a difference. D also has storage
- Janice Caron (16/19) Nov 27 2007 Make that THREE flavours in D
- Jarrett Billingsley (8/27) Nov 28 2007 Read the conference slides? In fact you even guessed the keyword --
- Janice Caron (34/37) Nov 26 2007 It seems to me that the following is still ambiguous:
- Walter Bright (8/56) Nov 27 2007 (b). Think of it this way:
- Janice Caron (8/13) Nov 27 2007 Ah, but the natural interpretation of const(...) is that /everything/
- Walter Bright (5/15) Nov 27 2007 That's only if one thinks that const, when applied to a function, also
- Janice Caron (14/20) Nov 27 2007 I do understand. But I'm thinking of the poor programmer who hasn't
- Walter Bright (6/32) Nov 27 2007 Since a const array cannot be implicitly cast to a non-const, he'll get
- Janice Caron (20/27) Nov 27 2007 Not necessarily. They might be relying on implicit cast to const in
- Walter Bright (2/37) Nov 27 2007
- Brad Roberts (6/40) Nov 27 2007 Also, don't forget the array vs slice changes that have been proposed in...
- Bill Baxter (6/26) Nov 27 2007 What if it were
- David Gileadi (9/42) Nov 27 2007 While maybe a bit of typing, I really like the const(this) form--its
- Janice Caron (6/14) Nov 27 2007 For what it's worth, I completely agree with this. I think it's a fine
- Don Clugston (2/19) Nov 28 2007 Me too.
- Janice Caron (63/78) Nov 28 2007 A thought occurs to me. (And it's a good one). Since we're considering
- Christopher Wright (20/21) Nov 28 2007 I think so, too. It'd help whenever I have a hairy method with lots of
- Bill Baxter (9/34) Nov 28 2007 I suspect you'd also be able to do something along the lines of:
- Bill Baxter (18/59) Nov 28 2007 I guess in C++ you'd do that by making a const reference to x:
- Janice Caron (2/3) Nov 28 2007 I guess that should really be "const declarations", not "const
- Jason House (2/19) Nov 29 2007 I like it too. It's extremely clear and never ambiguous.
Any update on the status of the const/invariant changes? I'm using D 2.0 in some things, and would hate to learn to do it X way, only to have it changed on me.
Nov 26 2007
Denton Cockburn wrote:Any update on the status of the const/invariant changes?Yes, it's about done.I'm using D 2.0 in some things, and would hate to learn to do it X way, only to have it changed on me.While the semantic changes are extensive, I've found to my surprise that little has to change in source code that uses const.
Nov 26 2007
Walter Bright Wrote:Denton Cockburn wrote:How about documentation of how const will work. Is this essentially what was originally posted in the "const is broken" thread? Or are there new surprises in store for us?Any update on the status of the const/invariant changes?Yes, it's about done.I'm using D 2.0 in some things, and would hate to learn to do it X way, only to have it changed on me.While the semantic changes are extensive, I've found to my surprise that little has to change in source code that uses const.
Nov 26 2007
Jason House wrote:Walter Bright Wrote:I don't remember the details of that, but the nutshell version is: 1) no more final for variables 2) no more 'head const' or 'tail const', it's all just 'const' 3) ditto (2) for invariant It should be working as one would intuitively expect it to.Denton Cockburn wrote:How about documentation of how const will work. Is this essentially what was originally posted in the "const is broken" thread? Or are there new surprises in store for us?Any update on the status of the const/invariant changes?Yes, it's about done.
Nov 26 2007
Walter Bright Wrote:Jason House wrote:Sounds about the same... I remember it as "transitive const". Looking at changeset 512, I can see only a few small changes: * const after functions for const functions * "static const" instead of just "const" for a few global constants Is the 2nd one just code cleanup or does it have a deeper reason? PS: It really is interesting to see just how little you've changed over the previous code. If I remember right, the original framework caused grumblings about how hard it was to use string constants. Since very little of that code has changed (I'm guessing), has this become any easier for developers? PSS: I haven't used D 2.0 yet, so my questions may be ignorant. It wasn't anything specific to D 2.0 except that Tango didn't work on it and gdc didn't support it. Mac support was more important to me than cost support.How about documentation of how const will work. Is this essentially what was originally posted in the "const is broken" thread? Or are there new surprises in store for us?I don't remember the details of that, but the nutshell version is: 1) no more final for variables 2) no more 'head const' or 'tail const', it's all just 'const' 3) ditto (2) for invariant It should be working as one would intuitively expect it to.
Nov 26 2007
On Mon, 26 Nov 2007 14:11:25 -0800, Walter Bright wrote:Jason House wrote:Is the keyword in this context now a syntax error?Walter Bright Wrote:I don't remember the details of that, but the nutshell version is: 1) no more final for variablesDenton Cockburn wrote:How about documentation of how const will work. Is this essentially what was originally posted in the "const is broken" thread? Or are there new surprises in store for us?Any update on the status of the const/invariant changes?Yes, it's about done.2) no more 'head const' or 'tail const', it's all just 'const'Does that mean that if X is const then neither the bits in X and the bits referenced by X can be modified (though the X symbol)?3) ditto (2) for invariantDoes that mean that if X is invariant then neither the bits in X and the bits referenced by X can be modified by anything?It should be working as one would intuitively expect it to.If the answer is 'yes' to the couple of questions above ... (a) is there a form of the syntax that allows 'X' to be modified but not what it references? (b) is there a form that prevents 'X' from being modified but allows what it references to be modified? -- Derek (skype: derek.j.parnell) Melbourne, Australia 27/11/2007 9:27:28 AM
Nov 26 2007
Derek Parnell wrote:On Mon, 26 Nov 2007 14:11:25 -0800, Walter Bright wrote:It's just ignored.Jason House wrote:Is the keyword in this context now a syntax error?Walter Bright Wrote:I don't remember the details of that, but the nutshell version is: 1) no more final for variablesDenton Cockburn wrote:How about documentation of how const will work. Is this essentially what was originally posted in the "const is broken" thread? Or are there new surprises in store for us?Any update on the status of the const/invariant changes?Yes, it's about done.Const and invariant are transitive. C++ const is not transitive, leading to programmers establishing a *convention* for transitive const. But it being an unenforced convention means it is not reliable.2) no more 'head const' or 'tail const', it's all just 'const'Does that mean that if X is const then neither the bits in X and the bits referenced by X can be modified (though the X symbol)?Right.3) ditto (2) for invariantDoes that mean that if X is invariant then neither the bits in X and the bits referenced by X can be modified by anything?Yes, transitive const applies downwards, not upwards.It should be working as one would intuitively expect it to.If the answer is 'yes' to the couple of questions above ... (a) is there a form of the syntax that allows 'X' to be modified but not what it references?(b) is there a form that prevents 'X' from being modified but allows what it references to be modified?No. There is no language typing support for 'logical const' (i.e. const structures with mutable members). Many C++ people have argued passionately for logical const, but I have become strongly convinced that the notion is fatally flawed.
Nov 26 2007
"Walter Bright" wroteDerek Parnell wrote:Before, I could declare an array of const characters. Essentially, the array structure could be modified, but the characters pointed to by the array could not. i.e. const(char)[] myString = "hello"; However, in this case, I could slice my string like so myString = myString[0..4] // set to "hell" The way you are talking this is no longer possible? Because now I can only have a fully const array which means you cannot change the pointer in the array? Just trying to clarify :) -SteveOn Mon, 26 Nov 2007 14:11:25 -0800, Walter Bright wrote:Const and invariant are transitive. C++ const is not transitive, leading to programmers establishing a *convention* for transitive const. But it being an unenforced convention means it is not reliable.2) no more 'head const' or 'tail const', it's all just 'const'Does that mean that if X is const then neither the bits in X and the bits referenced by X can be modified (though the X symbol)?
Nov 26 2007
Steven Schveighoffer wrote:"Walter Bright" wroteIt still works.Derek Parnell wrote:Before, I could declare an array of const characters. Essentially, the array structure could be modified, but the characters pointed to by the array could not. i.e. const(char)[] myString = "hello"; However, in this case, I could slice my string like so myString = myString[0..4] // set to "hell" The way you are talking this is no longer possible?On Mon, 26 Nov 2007 14:11:25 -0800, Walter Bright wrote:Const and invariant are transitive. C++ const is not transitive, leading to programmers establishing a *convention* for transitive const. But it being an unenforced convention means it is not reliable.2) no more 'head const' or 'tail const', it's all just 'const'Does that mean that if X is const then neither the bits in X and the bits referenced by X can be modified (though the X symbol)?Because now I can only have a fully const array which means you cannot change the pointer in the array?A "fully const array" would be declared as: const(char[]) myString; or just: const char[] myString;
Nov 26 2007
On Mon, 26 Nov 2007 15:02:57 -0800, Walter Bright wrote:Derek Parnell wrote:And I assume that 'transitive' in this context means that if X is const then it's members are const, and in turn their members are const, ... all the way down. Does this mean that the syntax 'const char[] X' and 'const (char)[] X' are now the same thing?Const and invariant are transitive. C++ const is not transitive, leading to programmers establishing a *convention* for transitive const. But it being an unenforced convention means it is not reliable.2) no more 'head const' or 'tail const', it's all just 'const'Does that mean that if X is const then neither the bits in X and the bits referenced by X can be modified (though the X symbol)?What would that syntax be? Can you give examples for arrays, AA, classes and structs?Right.3) ditto (2) for invariantDoes that mean that if X is invariant then neither the bits in X and the bits referenced by X can be modified by anything?Yes, transitive const applies downwards, not upwards.It should be working as one would intuitively expect it to.If the answer is 'yes' to the couple of questions above ... (a) is there a form of the syntax that allows 'X' to be modified but not what it references?How would I specify that I have a buffer of bytes and I can't change its location but I can change its contents? -- Derek (skype: derek.j.parnell) Melbourne, Australia 27/11/2007 10:20:49 AM(b) is there a form that prevents 'X' from being modified but allows what it references to be modified?No. There is no language typing support for 'logical const' (i.e. const structures with mutable members). Many C++ people have argued passionately for logical const, but I have become strongly convinced that the notion is fatally flawed.
Nov 26 2007
Derek Parnell wrote:On Mon, 26 Nov 2007 15:02:57 -0800, Walter Bright wrote:Yes.Derek Parnell wrote:And I assume that 'transitive' in this context means that if X is const then it's members are const, and in turn their members are const, ... all the way down.Const and invariant are transitive. C++ const is not transitive, leading to programmers establishing a *convention* for transitive const. But it being an unenforced convention means it is not reliable.2) no more 'head const' or 'tail const', it's all just 'const'Does that mean that if X is const then neither the bits in X and the bits referenced by X can be modified (though the X symbol)?Does this mean that the syntax 'const char[] X' and 'const (char)[] X' are now the same thing?No. "const char[] X;" and "const(char[]) X;" mean the same thing.Just put () around the part of the type you wish to be const. See above examples.What would that syntax be? Can you give examples for arrays, AA, classes and structs?Right.3) ditto (2) for invariantDoes that mean that if X is invariant then neither the bits in X and the bits referenced by X can be modified by anything?Yes, transitive const applies downwards, not upwards.It should be working as one would intuitively expect it to.If the answer is 'yes' to the couple of questions above ... (a) is there a form of the syntax that allows 'X' to be modified but not what it references?You can't. A good question would be what would be the purpose of such?How would I specify that I have a buffer of bytes and I can't change its location but I can change its contents?(b) is there a form that prevents 'X' from being modified but allows what it references to be modified?No. There is no language typing support for 'logical const' (i.e. const structures with mutable members). Many C++ people have argued passionately for logical const, but I have become strongly convinced that the notion is fatally flawed.
Nov 26 2007
On Mon, 26 Nov 2007 16:36:17 -0800, Walter Bright wrote:Derek Parnell wrote:I am under the impression that this is a fairly common way of doing things. byte[] bitmap; bitmap = LoadBitMapFromFile("worldroadmap.bmp"); GammaAdjust(bitmap, 0.20); ---- dchar[] Text; Text = ReadTextFile("collectedshakespeare.txt"); ConvertToLowercase(Text); ---- In other words, there maybe valid reasons to modify data in-place rather than create a modified copy of the data. -- Derek (skype: derek.j.parnell) Melbourne, Australia 27/11/2007 11:53:31 AMHow would I specify that I have a buffer of bytes and I can't change its location but I can change its contents?You can't. A good question would be what would be the purpose of such?
Nov 26 2007
Derek Parnell wrote:I am under the impression that this is a fairly common way of doing things. byte[] bitmap; bitmap = LoadBitMapFromFile("worldroadmap.bmp"); GammaAdjust(bitmap, 0.20);void GammaAdjust(ref byte[] bitmap,float gamma) ? regards, frank
Nov 26 2007
0ffh wrote:Derek Parnell wrote:byte[] bitmap; bitmap = LoadBitMapFromFile("worldroadmap.bmp"); byte[] same_bitmap = bitmap; GammaAdjust(bitmap, 0.20); assert(bitmap.ptr is same_bitmap.ptr, "Error GammaAdjust not supposed to change the bitmap pointer"); Sometimes it's convenient to have more than one reference to the same buffer around. --bbI am under the impression that this is a fairly common way of doing things. byte[] bitmap; bitmap = LoadBitMapFromFile("worldroadmap.bmp"); GammaAdjust(bitmap, 0.20);void GammaAdjust(ref byte[] bitmap,float gamma) ?
Nov 26 2007
Dr. Egon Spengler: Don't cross the streams. =)
Nov 26 2007
Bill Baxter wrote:0ffh wrote:I'm not sure why one would need protection against changing the bitmap pointer. GammaAdjust should just take a byte[], not a ref byte[].Derek Parnell wrote:byte[] bitmap; bitmap = LoadBitMapFromFile("worldroadmap.bmp"); byte[] same_bitmap = bitmap; GammaAdjust(bitmap, 0.20); assert(bitmap.ptr is same_bitmap.ptr, "Error GammaAdjust not supposed to change the bitmap pointer"); Sometimes it's convenient to have more than one reference to the same buffer around.I am under the impression that this is a fairly common way of doing things. byte[] bitmap; bitmap = LoadBitMapFromFile("worldroadmap.bmp"); GammaAdjust(bitmap, 0.20);void GammaAdjust(ref byte[] bitmap,float gamma) ?
Nov 26 2007
On Mon, 26 Nov 2007 21:24:13 -0800, Walter Bright wrote:I'm not sure why one would need protection against changing the bitmap pointer. GammaAdjust should just take a byte[], not a ref byte[].byte[] bitmap; bitmap = LoadBitMapFromFile("worldroadmap.bmp"); GammaAdjust(bitmap, 0.20); Render(device, bitmap); If the 'GammaAdjust' routine changed the pointer then 'Render' routine would not display the adjusted bitmap. So I would like to tell the compiler that 'GammaAdjust' is not allowed to change the pointer and thus if (at compile time) it does so the compiler should tell me of the error. -- Derek (skype: derek.j.parnell) Melbourne, Australia 27/11/2007 5:28:39 PM
Nov 26 2007
On 11/27/07, Derek Parnell <derek nomail.afraid.org> wrote:On Mon, 26 Nov 2007 21:24:13 -0800, Walter Bright wrote:The GammaAdjust routine /cannot/ change the pointer, because it is passed in by value, not by reference. I guess it could change its own local copy of the pointer, but that would just be a bug local to the function.I'm not sure why one would need protection against changing the bitmap pointer. GammaAdjust should just take a byte[], not a ref byte[].byte[] bitmap; bitmap = LoadBitMapFromFile("worldroadmap.bmp"); GammaAdjust(bitmap, 0.20); Render(device, bitmap); If the 'GammaAdjust' routine changed the pointer then 'Render' routine would not display the adjusted bitmap.
Nov 26 2007
Janice Caron wrote:I guess it could change its own local copy of the pointer, but that would just be a bug local to the function.One which, I would think, should be caught by the type system. However, if there's no 'final', I guess this can't be done. On the other hand, maybe the compiler should just emit a warning when a passed-by-value parameter is written to. If you really do want to change your local copy of a parameter you can always copy it to a variable. Thanks, Nathan Reed
Nov 26 2007
On Mon, 26 Nov 2007 23:23:41 -0800, Nathan Reed wrote:Janice Caron wrote:I'm talking about having the compiler help catch coding mistakes at compile time. In this case, the compiler can only know that it is a mistake to (attempt to) modify the pointer if the coder tells it that the design forbids that behaviour. Therefore we need to have form of syntax to help the compiler help the coder. -- Derek (skype: derek.j.parnell) Melbourne, Australia 27/11/2007 6:29:07 PMI guess it could change its own local copy of the pointer, but that would just be a bug local to the function.One which, I would think, should be caught by the type system. However, if there's no 'final', I guess this can't be done. On the other hand, maybe the compiler should just emit a warning when a passed-by-value parameter is written to. If you really do want to change your local copy of a parameter you can always copy it to a variable.
Nov 26 2007
Derek Parnell wrote:On Mon, 26 Nov 2007 23:23:41 -0800, Nathan Reed wrote:If you're worried about the implementer doing the wrong thing then you could argue that the same applies to all arguments. void foo(int x) { x = 10; /* oops! did I mean to do that? Or was I hoping the user would see it? */ } But there is a difference in that if you're really worried about that possibility then you can make it foo(const int), but without head const you can't do the same thing for just the pointer. But is it important enough to justify the extra complication? We get by in D1.0 without const at all, after all. Java gets by without it too. I'm ready to accept a const that can't express every nuance if it enables greater simplicity. --bbJanice Caron wrote:I'm talking about having the compiler help catch coding mistakes at compile time. In this case, the compiler can only know that it is a mistake to (attempt to) modify the pointer if the coder tells it that the design forbids that behaviour. Therefore we need to have form of syntax to help the compiler help the coder.I guess it could change its own local copy of the pointer, but that would just be a bug local to the function.One which, I would think, should be caught by the type system. However, if there's no 'final', I guess this can't be done. On the other hand, maybe the compiler should just emit a warning when a passed-by-value parameter is written to. If you really do want to change your local copy of a parameter you can always copy it to a variable.
Nov 27 2007
Bill Baxter wrote:But is it important enough to justify the extra complication? We get by in D1.0 without const at all, after all. Java gets by without it too. I'm ready to accept a const that can't express every nuance if it enables greater simplicity.It is clear that the previous implementation of const, while it allowed for very nuanced control, was worthless because it was too complicated. Going back and rethinking things, it is apparent that things like final only serve a local purpose, not an API one, and so have limited utility for their complexity.
Nov 27 2007
On Tue, 27 Nov 2007 06:54:40 +0000, Janice Caron wrote:On 11/27/07, Derek Parnell <derek nomail.afraid.org> wrote:I'm sorry I'm not getting my request out clear enough. I *know* that at run time the GammaAdjust routine cannot effectively change the pointer. But that is not what I'm saying. I would like the compiler to tell me at /compile/ time that I've incorrectly attempted to change a pointer that has been designed to remain unchanged. I would like to avoid waiting for this to only become apparent at /run/ time. -- Derek (skype: derek.j.parnell) Melbourne, Australia 27/11/2007 6:24:56 PMOn Mon, 26 Nov 2007 21:24:13 -0800, Walter Bright wrote:The GammaAdjust routine /cannot/ change the pointer, because it is passed in by value, not by reference. I guess it could change its own local copy of the pointer, but that would just be a bug local to the function.I'm not sure why one would need protection against changing the bitmap pointer. GammaAdjust should just take a byte[], not a ref byte[].byte[] bitmap; bitmap = LoadBitMapFromFile("worldroadmap.bmp"); GammaAdjust(bitmap, 0.20); Render(device, bitmap); If the 'GammaAdjust' routine changed the pointer then 'Render' routine would not display the adjusted bitmap.
Nov 26 2007
Derek Parnell wrote:On Mon, 26 Nov 2007 21:24:13 -0800, Walter Bright wrote:Change GammaAdjust from (ref byte[] bitmap) to (byte[] bitmap), and it cannot change the caller's copy.I'm not sure why one would need protection against changing the bitmap pointer. GammaAdjust should just take a byte[], not a ref byte[].byte[] bitmap; bitmap = LoadBitMapFromFile("worldroadmap.bmp"); GammaAdjust(bitmap, 0.20); Render(device, bitmap); If the 'GammaAdjust' routine changed the pointer then 'Render' routine would not display the adjusted bitmap. So I would like to tell the compiler that 'GammaAdjust' is not allowed to change the pointer and thus if (at compile time) it does so the compiler should tell me of the error.
Nov 27 2007
"Derek Parnell" wroteOn Mon, 26 Nov 2007 21:24:13 -0800, Walter Bright wrote:I think you are missing something here. Let's view this as it really is, a pointer with a length: void GammaAdjust(byte *bitmap, int length, double adjustment) { // want to realloc bitmap? byte *tmp = bitmap; bitmap = malloc(length + 1); // don't really know the right way to do this :) memcpy(bitmap, tmp, length); bitmap[length] = 5; // work on bitmap... } Now does any reasonable C coder expect this to work correctly? no. It seems a bit fuzzy because in D we think of arrays as pointers, but they are really structures, passed by value. Let's assume your wish was granted and headconst was available. Now the code becomes: void GammaAdjust(headconst byte *bitmap, int length, double adjustment) { // want to realloc bitmap? oops! can't do it, I'll just use a different variable byte *tmp = malloc(length + 1); memcpy(tmp, bitmap, length); tmp[length] = 5; // work on tmp... } our coder has now realized that he cannot change the bitmap pointer, so he just allocates a new one. This is the same as the previous example, except now we just use a different variable. You have not solved the problem, and that is: any coder who does not understand the semantics of variable passing is not going to be saved by anything the compiler can enforce. I believe the second example is more obvious than the first, but both are still obvious to me, and even the example where byte[] is used is obvious to me :) I think what we need is a better explanation to new coders on how arrays work and are passed to functions. I agree with Walter's position regarding head const. -SteveI'm not sure why one would need protection against changing the bitmap pointer. GammaAdjust should just take a byte[], not a ref byte[].byte[] bitmap; bitmap = LoadBitMapFromFile("worldroadmap.bmp"); GammaAdjust(bitmap, 0.20); Render(device, bitmap); If the 'GammaAdjust' routine changed the pointer then 'Render' routine would not display the adjusted bitmap. So I would like to tell the compiler that 'GammaAdjust' is not allowed to change the pointer and thus if (at compile time) it does so the compiler should tell me of the error.
Nov 27 2007
On Tue, 27 Nov 2007 09:41:03 -0500, Steven Schveighoffer wrote:"Derek Parnell" wroteArrrgh! I'm talking about accidently or inadvertant attempts to change a pointer's value. I'm talking about allowing the compiler to help the coder. void GammaAdjust(byte* const(bitmap), int length, double adjustment) { // want to realloc bitmap? byte *tmp = bitmap; bitmap = malloc(length + 1); // BANG! Compiler shouldn't allow this. memcpy(bitmap, tmp, length); bitmap[length] = 5; // But this is okay. // work on bitmap... } -- Derek Parnell Melbourne, Australia skype: derek.j.parnellOn Mon, 26 Nov 2007 21:24:13 -0800, Walter Bright wrote:I think you are missing something here. Let's view this as it really is, a pointer with a length: void GammaAdjust(byte *bitmap, int length, double adjustment) { // want to realloc bitmap? byte *tmp = bitmap; bitmap = malloc(length + 1); // don't really know the right way to do this :) memcpy(bitmap, tmp, length); bitmap[length] = 5; // work on bitmap... } Now does any reasonable C coder expect this to work correctly? no.I'm not sure why one would need protection against changing the bitmap pointer. GammaAdjust should just take a byte[], not a ref byte[].byte[] bitmap; bitmap = LoadBitMapFromFile("worldroadmap.bmp"); GammaAdjust(bitmap, 0.20); Render(device, bitmap); If the 'GammaAdjust' routine changed the pointer then 'Render' routine would not display the adjusted bitmap. So I would like to tell the compiler that 'GammaAdjust' is not allowed to change the pointer and thus if (at compile time) it does so the compiler should tell me of the error.
Nov 27 2007
"Derek Parnell" wroteOn Tue, 27 Nov 2007 09:41:03 -0500, Steven Schveighoffer wrote:I understood what you meant. My point is that the compiler cannot prevent *all* types of mistakes that you are talking about. So in my opinion, the benefit of including such a feature is very minimal compared to the complexity required to be added to the compiler. -Steve"Derek Parnell" wroteArrrgh! I'm talking about accidently or inadvertant attempts to change a pointer's value. I'm talking about allowing the compiler to help the coder.On Mon, 26 Nov 2007 21:24:13 -0800, Walter Bright wrote:I think you are missing something here. Let's view this as it really is, a pointer with a length: void GammaAdjust(byte *bitmap, int length, double adjustment) { // want to realloc bitmap? byte *tmp = bitmap; bitmap = malloc(length + 1); // don't really know the right way to do this :) memcpy(bitmap, tmp, length); bitmap[length] = 5; // work on bitmap... } Now does any reasonable C coder expect this to work correctly? no.I'm not sure why one would need protection against changing the bitmap pointer. GammaAdjust should just take a byte[], not a ref byte[].byte[] bitmap; bitmap = LoadBitMapFromFile("worldroadmap.bmp"); GammaAdjust(bitmap, 0.20); Render(device, bitmap); If the 'GammaAdjust' routine changed the pointer then 'Render' routine would not display the adjusted bitmap. So I would like to tell the compiler that 'GammaAdjust' is not allowed to change the pointer and thus if (at compile time) it does so the compiler should tell me of the error.
Nov 27 2007
On Tue, 27 Nov 2007 16:57:36 -0500, Steven Schveighoffer wrote:I understood what you meant. My point is that the compiler cannot prevent *all* types of mistakes that you are talking about. So in my opinion, the benefit of including such a feature is very minimal compared to the complexity required to be added to the compiler.Thank you. -- Derek (skype: derek.j.parnell) Melbourne, Australia 28/11/2007 10:46:15 AM
Nov 27 2007
On Tue, 27 Nov 2007 10:48:42 +0900, Bill Baxter wrote:0ffh wrote:Okay, I get it. We don't actually need const/invariant at all. Instead we just sprinkle our code with asserts to catch these compile-time errors at run-time. Neat. -- Derek (skype: derek.j.parnell) Melbourne, Australia 27/11/2007 5:37:49 PMDerek Parnell wrote:byte[] bitmap; bitmap = LoadBitMapFromFile("worldroadmap.bmp"); byte[] same_bitmap = bitmap; GammaAdjust(bitmap, 0.20); assert(bitmap.ptr is same_bitmap.ptr, "Error GammaAdjust not supposed to change the bitmap pointer");I am under the impression that this is a fairly common way of doing things. byte[] bitmap; bitmap = LoadBitMapFromFile("worldroadmap.bmp"); GammaAdjust(bitmap, 0.20);void GammaAdjust(ref byte[] bitmap,float gamma) ?
Nov 26 2007
Derek Parnell wrote:Okay, I get it. We don't actually need const/invariant at all. Instead we just sprinkle our code with asserts to catch these compile-time errors at run-time. Neat.I think this new const sounds like a reasonable compromise to get simple yet still useful const semantics. People will never agree 100% on how this should work, and comments like this one doesn't help anything. Walter already said there will be no head/tail const. Just const. Why bother asking how to do head const? (Or have I completely misunderstood things?)
Nov 26 2007
On Tue, 27 Nov 2007 07:47:45 +0100, Tomas Lindquist Olsen wrote:Derek Parnell wrote:I agree that the const as now proposed is simple and still useful. I'm sorry you see my comment as unhelpful.Okay, I get it. We don't actually need const/invariant at all. Instead we just sprinkle our code with asserts to catch these compile-time errors at run-time. Neat.I think this new const sounds like a reasonable compromise to get simple yet still useful const semantics. People will never agree 100% on how this should work, and comments like this one doesn't help anything.Walter already said there will be no head/tail const. Just const. Why bother asking how to do head const? (Or have I completely misunderstood things?)You have not misunderstood. As I'm sure Walter will be the first to agree, he is not all-knowing. I believe that there has been times when Walter has said "X", defended "X" vigorously against "Y", but then something happens and we get "Y" implemented instead. I think that Walter is saying that he (currently), after much thought and deliberation, has decided that there is no benefit to any coder in implementing the head const paradigm in D. Therefore those unfortunates such as myself, that can't yet grasp why there is no benefit, may feel obliged to continue asking for an explanation or assistance about how we could implement head const without the compiler helping us. -- Derek (skype: derek.j.parnell) Melbourne, Australia 27/11/2007 5:55:45 PM
Nov 26 2007
Derek Parnell wrote:I think that Walter is saying that he (currently), after much thought and deliberation, has decided that there is no benefit to any coder in implementing the head const paradigm in D. Therefore those unfortunates such as myself, that can't yet grasp why there is no benefit, may feel obliged to continue asking for an explanation or assistance about how we could implement head const without the compiler helping us.Head const turned out to be an unexplainable, incomprehensible feature. A feature that is incomprehensible is unusable, unworkable, and a complete waste of time. It's also become apparent that a lot of people stick with D 1.0, and refuse to move to 2.0, because of the incomprehensibility of head/tail const. Head const (aka 'final'), had another fatal flaw. If you took the address of it, you had a const that was not transitive.
Nov 27 2007
Derek Parnell wrote:On Tue, 27 Nov 2007 07:47:45 +0100, Tomas Lindquist Olsen wrote: [...] I think that Walter is saying that he (currently), after much thought and deliberation, has decided that there is no benefit to any coder in implementing the head const paradigm in D. Therefore those unfortunates such as myself, that can't yet grasp why there is no benefit, may feel obliged to continue asking for an explanation or assistance about how we could implement head const without the compiler helping us.Well, I don't quite see your problem with assert. Earlier you said:Okay, I get it. We don't actually need const/invariant at all. Instead we just sprinkle our code with asserts to catch these compile-time errors at run-time. Neat.I think you forget (or ignore) something elemental here, which is that runtime not equals runtime, and that you'll use you asserts only to make sure at "test/debug"-runtime that you (and all of your co-workers) didn't fup it. I postulate that even with head const available, you'll still have to test your software. Or do you go "Ah, finally it compiles! Call in the delivery boy!"? I think the difference is not so grand as you make it. regards, frank
Nov 27 2007
On Tue, 27 Nov 2007 12:12:51 +0100, 0ffh wrote:Derek Parnell wrote:Neither did I forget nor ignore. My 'assert' comment was a (poor) example of sarcasm. I didn't really mean it. I just said it as an extreme statement to highlight that I thought it was a idea not worthy of further consideration.On Tue, 27 Nov 2007 07:47:45 +0100, Tomas Lindquist Olsen wrote: [...] I think that Walter is saying that he (currently), after much thought and deliberation, has decided that there is no benefit to any coder in implementing the head const paradigm in D. Therefore those unfortunates such as myself, that can't yet grasp why there is no benefit, may feel obliged to continue asking for an explanation or assistance about how we could implement head const without the compiler helping us.Well, I don't quite see your problem with assert. Earlier you said:Okay, I get it. We don't actually need const/invariant at all. Instead we just sprinkle our code with asserts to catch these compile-time errors at run-time. Neat.I think you forget (or ignore) something elemental here, which is that runtime not equals runtime, and that you'll use you asserts only to make sure at "test/debug"-runtime that you (and all of your co-workers) didn't fup it.I postulate that even with head const available, you'll still have to test your software. Or do you go "Ah, finally it compiles! Call in the delivery boy!"?And why do you assume that I think otherwise?I think the difference is not so grand as you make it.I do not think it as "so grand", whatever that means. My point is that any help that a compiler can give to the coder in preventing coding errors is a worthwhile pursuit. Sure, there are diminishing returns and maybe this is one of them. I'm not sure because I have not analyzed any empirical statistics. I am simply saying, and this seems to be very hard to get across, that if there is some syntax to express the design concept of "the pointer may not be modified but the items pointed to can be", then the compiler can detect at compile time when the coder attempts to change the pointer, and issue the appropriate warning. A compiler exists to make life easier for the coder. If this truely is a case where "Head const turned out to be an unexplainable, incomprehensible feature." and/or is too hard to implement, then I'll go with the flow. I haven't seen evidence of that being the case yet, regardless of Walter's statements so far. -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
Nov 27 2007
Derek Parnell wrote:On Tue, 27 Nov 2007 12:12:51 +0100, 0ffh wrote:Neither am I. But I've lived a reasonably long life coding without "const" of any kind, so I really wonder what all the fuzz is about, when a simple, straightforward implementation (probably better than none) is not enough.I think the difference is not so grand as you make it.I do not think it as "so grand", whatever that means. My point is that any help that a compiler can give to the coder in preventing coding errors is a worthwhile pursuit. Sure, there are diminishing returns and maybe this is one of them. I'm not sure because I have not analyzed any empirical statistics.I am simply saying, and this seems to be very hard to get across, that if there is some syntax to express the design concept of "the pointer may not be modified but the items pointed to can be", then the compiler can detect at compile time when the coder attempts to change the pointer, and issue the appropriate warning.Well, the point is not so hard to get across as you think. I agree that, ideally, any coding error should be flagged by the compiler. I suppose we agree that this gets hard as the potential errors get nontrivial. Give me some room to hyperbole, and I'll tell you this: We can make a super coding-error resistant language by just requiring that every function must be coded in triplicate, in different languages. The compiler will check if all three implementations are identical, otherwise it'll fail with an error. This is where you're heading, albeit from a long way away. =)A compiler exists to make life easier for the coder. If this truely is a case where "Head const turned out to be an unexplainable, incomprehensible feature." and/or is too hard to implement, then I'll go with the flow. I haven't seen evidence of that being the case yet, regardless of Walter's statements so far.Actually, I'll now change hats and tell you my opinion: Simple features should be easily reachable, advanced features should exist. So I think that simple const as is now planned should be reachable using a simple syntax, and advanced concepts of const should ideally be possible, but in case of doubt by using a more complicated syntax. I don't think that the last const-proposal by Walter was really much too complicated. The problem is more that most people here were immediately trying to grok it in all it's aspects, and some were a bit turned off that some of those tries have not met instant gratification. And apart from all that - from a /very/ personal POV - I don't need it. =) regards, frank
Nov 27 2007
"Derek Parnell" <derek psych.ward> kirjoitti viestissä news:1vst9y1mnh6kz.tkg1phefemws$.dlg 40tude.net...My point is that any help that a compiler can give to the coder in preventing coding errors is a worthwhile pursuit. Sure, there are diminishing returns and maybe this is one of them. I'm not sure because I have not analyzed any empirical statistics. I am simply saying, and this seems to be very hard to get across, that if there is some syntax to express the design concept of "the pointer may not be modified but the items pointed to can be", then the compiler can detect at compile time when the coder attempts to change the pointer, and issue the appropriate warning. A compiler exists to make life easier for the coder. If this truely is a case where "Head const turned out to be an unexplainable, incomprehensible feature." and/or is too hard to implement, then I'll go with the flow. I haven't seen evidence of that being the case yet, regardless of Walter's statements so far.I believe head const is a feature that should exist. I'm just a bit unsure of how it should be integrated with the new version of const, since the main thing, IMO, is that it should be as simple as possible. We can, I think, basically separate constness into four categories (I'm not talking about invariants, just head and tail const): 1: no constness 2: tail constness 3: head constness 4: head and tail constness The syntax for cases 1 and 2 are now getting quite clear (I'll just use "ref" here in these examples): 1: void foo(ref byte[] bar) 2: void foo(ref const(byte[]) bar) - at least I think it would be this way... :) The cases for 3 and 4 could just basically be an extension of this, with the "ref" keyword basically required to mark head constness as follows: 3: void foo(const(ref) byte[] bar) 4: void foo(const(ref) const(byte[]) bar) I admit these cases looks ugly, but at least they tell exactly what is going on: the reference itself is constant, and in case four the type, as well. (As a side-note, I was at first considering the following syntax: 3: void foo(const(ref byte[]) bar) 4: void foo(const(ref const(byte[])) bar) but I believe the last case to be even more uglier than in the variant above and case 3 to be ambivalent: is the intent to make the reference constant, or the reference and the byte[] itself?)
Nov 28 2007
Derek Parnell wrote:If this truely is a case where "Head const turned out to be an unexplainable, incomprehensible feature." and/or is too hard to implement, then I'll go with the flow. I haven't seen evidence of that being the case yet, regardless of Walter's statements so far.The only person I know of who understood it was Andrei. This is despite many hours spent trying to explain it with pencil and paper, on whiteboards (at the D conference), and on the n.g. Now, I'll be the first to say I stink at explaining concepts to people, but I watched Andrei try and fail at this repeatedly, and Andrei is very good at explaining things. I do not know why it is so hard to explain, but it is, and it's clear I was bashing my head on a rock with it, and that rock was going to sink D 2.0 if it wasn't changed.
Nov 28 2007
On Wed, 28 Nov 2007 17:56:37 -0800, Walter Bright wrote:Derek Parnell wrote:... Head const ...The only person I know of who understood it was Andrei.I do not know why it is so hard to explain, but it is ...I though it was simply "the pointer can't change but what it points to can". Am I missing the true definition of Head Const here? If so, can someone please have a go at bringing me up to speed. If not, is that really so hard to explain? Also, what is the syntax now for declaring a const function that returns a const value? -- Derek (skype: derek.j.parnell) Melbourne, Australia 29/11/2007 2:29:41 PM
Nov 28 2007
"Derek Parnell" wroteAlso, what is the syntax now for declaring a const function that returns a const value?const const(int)* f(){ ... } or const(int)* f() const { ... } This REALLY REALLY needs an example in the docs. Walter, please do something about this. The const void f() example doesn't cut it, especially for C++ defectors. I had to ask this question a while back in the learn NG after carefully examining the docs :) Also, will the following compile? const int* f1() const {...} invariant int* f2() const {...} And if they do, what do they mean? -Steve
Nov 28 2007
Steven Schveighoffer wrote:"Derek Parnell" wroteYes.Also, what is the syntax now for declaring a const function that returns a const value?const const(int)* f(){ ... } or const(int)* f() const { ... } This REALLY REALLY needs an example in the docs. Walter, please do something about this. The const void f() example doesn't cut it, especially for C++ defectors. I had to ask this question a while back in the learn NG after carefully examining the docs :) Also, will the following compile?const int* f1() const {...}A const function returning an int*. The const here is just redundant.invariant int* f2() const {...}An invariant function returning an int*. The invariant overrides the const.And if they do, what do they mean?
Nov 28 2007
On Thu, 29 Nov 2007 05:02:29 -0000, Walter Bright <newshound1 digitalmars.com> wrote:Steven Schveighoffer wrote:What would be the point of an invariant method? A const method promises not to change any contents of the object. An invariant method makes the same promise. So there is no difference to the caller of such a method. I can't see that it make any difference inside the method either. Regards, Bruce.invariant int* f2() const {...}An invariant function returning an int*. The invariant overrides the const.
Nov 29 2007
On Nov 29, 2007 8:50 AM, Bruce Adams <tortoise_74 yeah.who.co.uk> wrote:What would be the point of an invariant method? A const method promises not to change any contents of the object. An invariant method makes the same promise. So there is no difference to the caller of such a method. I can't see that it make any difference inside the method either.It makes a difference. Watch... class A { int x; const int f() { return x; } invariant int g() { return x; } } A ma = A(3); writefln(ma.f()); /* error */ writefln(ma.g()); /* error */ const A ca = A(3); writefln(ca.f()); /* OK */ wriitefln(ca.g()); /* error */ invariant A ia = A(3); writefln(ca.f()); /* OK */ writefln(ia.g()); /* OK */
Nov 29 2007
Hope yall were paying attention and spotted that I screwed that up completely. It should of course have been: class A { this(int n) { x = n; } int x; const int f() { return x; } invariant int g() { return x; } } A ma = new A(3); writefln(ma.f()); /* OK */ writefln(ma.g()); /* error */ const A ca = new A(3); writefln(ca.f()); /* OK */ wriitefln(ca.g()); /* error */ invariant A iaTemp = cast(invariant(A)) new A(3); writefln(ia.f()); /* OK */ writefln(ia.g()); /* OK */ Anyway, here's the deal. When you declare a function as const, it means that the variable "this" is const during the function's execution. Likewise, when you declare a function as invariant, it means that the variable "this" in invariant during the function's execution. In both cases, the callee code will fail to compile if the function modifies any member variable. The difference between the two is visible at the caller site, however. A pointer can always be cast to const, so calling a function declared as const is always OK. However, only no pointer can ever implicitly cast to an invariant pointer (unless it was invariant to begin with), so code at the caller site which tries to call an invariant function will not compile, unless the class instance in invariant. Of course, getting an invariant instance in the first place requires a cast!
Nov 29 2007
Steven Schveighoffer wrote:"Derek Parnell" wroteCurrently: Yes if f1 returns the address of a global or 'null'. No if it tries to return pointer to member of the class. Should probably be: No always. (Since "const const int* f1" is a "repeated storage class error", putting the redundant const at the end should be an error too, I think)Also, what is the syntax now for declaring a const function that returns a const value?const const(int)* f(){ ... } or const(int)* f() const { ... } This REALLY REALLY needs an example in the docs. Walter, please do something about this. The const void f() example doesn't cut it, especially for C++ defectors. I had to ask this question a while back in the learn NG after carefully examining the docs :) Also, will the following compile? const int* f1() const {...}invariant int* f2() const {...}Same thing. Yes if you return a pointer that's not part of the class scope. No if you return something that is class scope. Should also be no on both counts I think.And if they do, what do they mean?They mean the compiler is too leniant. :-) --bb
Nov 28 2007
Walter Bright wrote:Derek Parnell wrote:My issue with the design wasn't so much with the conceptual complexity (though this was still a bit high) as with the complexity it promised to add to code. The const features in C++ are simpler from a semantic standpoint than the proposed const features in D, and yet they can complicate code tremendously. With D I would prefer to sacrifice a bit of functionality in exchange for simpler code. SeanIf this truely is a case where "Head const turned out to be an unexplainable, incomprehensible feature." and/or is too hard to implement, then I'll go with the flow. I haven't seen evidence of that being the case yet, regardless of Walter's statements so far.The only person I know of who understood it was Andrei. This is despite many hours spent trying to explain it with pencil and paper, on whiteboards (at the D conference), and on the n.g. Now, I'll be the first to say I stink at explaining concepts to people, but I watched Andrei try and fail at this repeatedly, and Andrei is very good at explaining things. I do not know why it is so hard to explain, but it is, and it's clear I was bashing my head on a rock with it, and that rock was going to sink D 2.0 if it wasn't changed.
Nov 29 2007
Walter Bright wrote:Derek Parnell wrote:I do. (Appologies, but:) "Poorly understood is poorly explained." Even if it was cosmology, black holes, or the behavior of your neighbor; once thoroughly understood, you should be able to convey it in understandable terms to your audience. So, either Andrei has to rethink the whole thing, or we have to assume that the state of the art is, er, diffuse. NO offense.If this truely is a case where "Head const turned out to be an unexplainable, incomprehensible feature." and/or is too hard to implement, then I'll go with the flow. I haven't seen evidence of that being the case yet, regardless of Walter's statements so far.The only person I know of who understood it was Andrei. This is despite many hours spent trying to explain it with pencil and paper, on whiteboards (at the D conference), and on the n.g. Now, I'll be the first to say I stink at explaining concepts to people, but I watched Andrei try and fail at this repeatedly, and Andrei is very good at explaining things. I do not know why it is so hard to explain, but it is, and it's clear I was bashing my head on a rock with it, and that rock was going to sink D 2.0 if it wasn't changed.
Dec 17 2007
Walter Bright wrote:I pass you a buffer that I've carefully pre-allocated for you to fill in. You shouldn't reallocate it but you should modify its contents. Having the function signature say "takes const-pointer-to-mutable-data" makes it clear that the function won't be allocating the buffer for you or reallocating it out from under you. Just passing the pointer by value is ok from the caller's perspective (you can't change what *my* pointer points to) but from the maintenance programmer's perspective there's nothing to prevent accidentally re-assigning that mutable pointer to some other buffer inside the function and incorrectly making changes there. --bb (who was just in the process of writing such a modify-this-buffer function in D1, sans const)How would I specify that I have a buffer of bytes and I can't change its location but I can change its contents?You can't. A good question would be what would be the purpose of such?
Nov 26 2007
Bill Baxter wrote:Walter Bright wrote:Okay, that's a feature. But wouldn't an assertion do the same for you, just a bit more wordy? regards, frankI pass you a buffer that I've carefully pre-allocated for you to fill in. You shouldn't reallocate it but you should modify its contents. Having the function signature say "takes const-pointer-to-mutable-data" makes it clear that the function won't be allocating the buffer for you or reallocating it out from under you. [...] --bb (who was just in the process of writing such a modify-this-buffer function in D1, sans const)How would I specify that I have a buffer of bytes and I can't change its location but I can change its contents?You can't. A good question would be what would be the purpose of such?
Nov 26 2007
0ffh wrote:Bill Baxter wrote:More wordy and not checked at compile time. But it may be that it's not important enough to warrant language support. --bbWalter Bright wrote:Okay, that's a feature. But wouldn't an assertion do the same for you, just a bit more wordy?I pass you a buffer that I've carefully pre-allocated for you to fill in. You shouldn't reallocate it but you should modify its contents. Having the function signature say "takes const-pointer-to-mutable-data" makes it clear that the function won't be allocating the buffer for you or reallocating it out from under you. [...] --bb (who was just in the process of writing such a modify-this-buffer function in D1, sans const)How would I specify that I have a buffer of bytes and I can't change its location but I can change its contents?You can't. A good question would be what would be the purpose of such?
Nov 26 2007
Bill Baxter wrote:Walter Bright wrote:Then just pass in the buffer[]. No need to pass *buffer* by reference.I pass you a buffer that I've carefully pre-allocated for you to fill in. You shouldn't reallocate it but you should modify its contents.How would I specify that I have a buffer of bytes and I can't change its location but I can change its contents?You can't. A good question would be what would be the purpose of such?
Nov 26 2007
Walter Bright wrote:Bill Baxter wrote:void foo(char[] pbuffer) { //assume this causes reallocation //assume there is no more space in place pbuffer ~= "a"; } void main() { char[] buffer = "test".dup; foo(buffer); buffer[0] = 'a' //crash } Right? ReganWalter Bright wrote:Then just pass in the buffer[]. No need to pass *buffer* by reference.I pass you a buffer that I've carefully pre-allocated for you to fill in. You shouldn't reallocate it but you should modify its contents.How would I specify that I have a buffer of bytes and I can't change its location but I can change its contents?You can't. A good question would be what would be the purpose of such?
Nov 27 2007
Regan Heath wrote:void foo(char[] pbuffer) { //assume this causes reallocation //assume there is no more space in place pbuffer ~= "a"; } void main() { char[] buffer = "test".dup; foo(buffer); buffer[0] = 'a' //crash } Right?No. foo() modifies its copy of pbuffer, which is not the same as buffer.
Nov 27 2007
Walter Bright wrote:Regan Heath wrote:Yes, but the underlying memory is reallocated so buffer no longer points to valid memory, right? Reganvoid foo(char[] pbuffer) { //assume this causes reallocation //assume there is no more space in place pbuffer ~= "a"; } void main() { char[] buffer = "test".dup; foo(buffer); buffer[0] = 'a' //crash } Right?No. foo() modifies its copy of pbuffer, which is not the same as buffer.
Nov 27 2007
Regan Heath schrieb:Walter Bright wrote:You missed a semicolon, so it does not compile :) Realloc does not destroy the original buffer. So your foo just make a modified copy, that is not visible for the caller. buffer will stay unchanged.Regan Heath wrote:Yes, but the underlying memory is reallocated so buffer no longer points to valid memory, right? Reganvoid foo(char[] pbuffer) { //assume this causes reallocation //assume there is no more space in place pbuffer ~= "a"; } void main() { char[] buffer = "test".dup; foo(buffer); buffer[0] = 'a' //crash } Right?No. foo() modifies its copy of pbuffer, which is not the same as buffer.
Nov 27 2007
Frank Benoit wrote:Regan Heath schrieb:'realloc' (the ANSI C version) free's the original buffer. Are you saying that when D extends an array buffer, and there is no space to extend in place, it always creates a 2nd copy of the data and leaves the original copy untouched? Because, I was under the impression that completely new copies were only made on concatenation in this form: char[] a = b ~ c; I'll try and code up a test case that exhibits the behaviour I'm worried about, but it's hard when I don't really have control of the array memory allocation/re-allocation itself.. or do I.. I wonder if this would fix the problem: void foo(const(char[]) pbuffer) { ... } would reallocation of the data pointer in this array be prevented? If so, I reckon we should be passing either: const(char[]) array ref char[] array; and never: char[] array ReganWalter Bright wrote:You missed a semicolon, so it does not compile :) Realloc does not destroy the original buffer. So your foo just make a modified copy, that is not visible for the caller. buffer will stay unchanged.Regan Heath wrote:Yes, but the underlying memory is reallocated so buffer no longer points to valid memory, right? Reganvoid foo(char[] pbuffer) { //assume this causes reallocation //assume there is no more space in place pbuffer ~= "a"; } void main() { char[] buffer = "test".dup; foo(buffer); buffer[0] = 'a' //crash } Right?No. foo() modifies its copy of pbuffer, which is not the same as buffer.
Nov 27 2007
Regan Heath wrote:Are you saying that when D extends an array buffer, and there is no space to extend in place, it always creates a 2nd copy of the data and leaves the original copy untouched?Seems like you were right about this. This seems to be the code in internal\gc\gc.d if (newlength > p.length) { size_t size = p.length * sizeelem; size_t cap = _gc.capacity(p.data); if (cap <= newsize) { if (cap >= 4096) { // Try to extend in-place auto u = _gc.extend(p.data, (newsize + 1) - cap, (newsize + 1) - cap); if (u) { goto L1; } } newdata = cast(byte *)_gc.malloc(newsize + 1); newdata[0 .. size] = p.data[0 .. size]; if (!(ti.next.flags() & 1)) _gc.hasNoPointers(newdata); } L1: newdata[size .. newsize] = 0; } Regan
Nov 27 2007
Frank Benoit, el 27 de noviembre a las 11:01 me escribiste:Regan Heath schrieb:I think you are missing an important point here: string concatenation is a fairly common case where is really obscure to figure out if the undelying pointer gets changed or not. When a user writes pbuffer ~= "a"; it's not very intuitive to expect a realocation and pbuffer.ptr change. This could lead to some hard to find bugs, because of the lack of explicitness and non-determinism (so to speak) where pbuffer ~= "a"; could lead or not to reallocation (or the fact that pbuffer[0] = 'a' will survive the local function and concatenation *may* survive or may not). -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- Hey you, would you help me to carry the stone? Open your heart, I'm coming home.Walter Bright wrote:You missed a semicolon, so it does not compile :) Realloc does not destroy the original buffer. So your foo just make a modified copy, that is not visible for the caller. buffer will stay unchanged.Regan Heath wrote:Yes, but the underlying memory is reallocated so buffer no longer points to valid memory, right? Reganvoid foo(char[] pbuffer) { //assume this causes reallocation //assume there is no more space in place pbuffer ~= "a"; } void main() { char[] buffer = "test".dup; foo(buffer); buffer[0] = 'a' //crash } Right?No. foo() modifies its copy of pbuffer, which is not the same as buffer.
Nov 27 2007
Leandro Lucarella wrote:Frank Benoit, el 27 de noviembre a las 11:01 me escribiste:Though in the calling method, the buffer length wouldn't change, so if there isn't a realloc, the change is still lost.Regan Heath schrieb:I think you are missing an important point here: string concatenation is a fairly common case where is really obscure to figure out if the undelying pointer gets changed or not. When a user writes pbuffer ~= "a"; it's not very intuitive to expect a realocation and pbuffer.ptr change.Walter Bright wrote:You missed a semicolon, so it does not compile :) Realloc does not destroy the original buffer. So your foo just make a modified copy, that is not visible for the caller. buffer will stay unchanged.Regan Heath wrote:Yes, but the underlying memory is reallocated so buffer no longer points to valid memory, right? Reganvoid foo(char[] pbuffer) { //assume this causes reallocation //assume there is no more space in place pbuffer ~= "a"; } void main() { char[] buffer = "test".dup; foo(buffer); buffer[0] = 'a' //crash } Right?No. foo() modifies its copy of pbuffer, which is not the same as buffer.This could lead to some hard to find bugs, because of the lack of explicitness and non-determinism (so to speak) where pbuffer ~= "a"; could lead or not to reallocation (or the fact that pbuffer[0] = 'a' will survive the local function and concatenation *may* survive or may not).
Nov 27 2007
Leandro Lucarella wrote:Frank Benoit, el 27 de noviembre a las 11:01 me escribiste:In fact I missed it too! I was actually more concerned that buffer would not longer point to valid memory. I eventually figured out that D does not reallocate the original pointer unless it can reallocate in place. If it cannot reallocate in place it creates a new copy of the data.Regan Heath schrieb:I think you are missing an important point here:Walter Bright wrote:You missed a semicolon, so it does not compile :) Realloc does not destroy the original buffer. So your foo just make a modified copy, that is not visible for the caller. buffer will stay unchanged.Regan Heath wrote:Yes, but the underlying memory is reallocated so buffer no longer points to valid memory, right? Reganvoid foo(char[] pbuffer) { //assume this causes reallocation //assume there is no more space in place pbuffer ~= "a"; } void main() { char[] buffer = "test".dup; foo(buffer); buffer[0] = 'a' //crash } Right?No. foo() modifies its copy of pbuffer, which is not the same as buffer.This could lead to some hard to find bugs, because of the lack of explicitness and non-determinism (so to speak) where pbuffer ~= "a"; could lead or not to reallocation (or the fact that pbuffer[0] = 'a' will survive the local function and concatenation *may* survive or may not).Actually concatenation wont survive either because buffer.length is not changed by the concatenation. eg. void foo(char[] pbuffer) { pbuffer ~= "a"; } void main() { char[] buffer = "test".dup; foo(buffer); writefln(buffer); } This will always output "test". It would only become non-deterministic if you coded: void main() { char[] buffer = "test".dup; foo(buffer); buffer = buffer.ptr[0..buffer.length+1] writefln(buffer); } as 99 times out of 100 you would get "testa" now, but the one time it cannot do an in place reallocation in foo there will be no "a" at the memory address following "test". As for: void foo(char[] pbuffer) { pbuffer[0] = 'a'; } this modification survives, but can be prevented with: void foo(invariant(char)[] pbuffer) { pbuffer[0] = 'a'; //error } and "string" will continue to be an alias for invariant(char)[] I imagine. In short, ignore me I was throwing crimson coloured fish in the air. Regan
Nov 27 2007
"Leandro Lucarella" wroteFrank Benoit, el 27 de noviembre a las 11:01 me escribiste:It is very deterministic actually. From http://www.digitalmars.com/d/arrays.html "Concatenation always creates a copy of its operands, even if one of the operands is a 0 length array" -SteveRegan Heath schrieb:I think you are missing an important point here: string concatenation is a fairly common case where is really obscure to figure out if the undelying pointer gets changed or not. When a user writes pbuffer ~= "a"; it's not very intuitive to expect a realocation and pbuffer.ptr change. This could lead to some hard to find bugs, because of the lack of explicitness and non-determinism (so to speak) where pbuffer ~= "a"; could lead or not to reallocation (or the fact that pbuffer[0] = 'a' will survive the local function and concatenation *may* survive or may not).Walter Bright wrote:You missed a semicolon, so it does not compile :) Realloc does not destroy the original buffer. So your foo just make a modified copy, that is not visible for the caller. buffer will stay unchanged.Regan Heath wrote:Yes, but the underlying memory is reallocated so buffer no longer points to valid memory, right? Reganvoid foo(char[] pbuffer) { //assume this causes reallocation //assume there is no more space in place pbuffer ~= "a"; } void main() { char[] buffer = "test".dup; foo(buffer); buffer[0] = 'a' //crash } Right?No. foo() modifies its copy of pbuffer, which is not the same as buffer.
Nov 27 2007
Steven Schveighoffer wrote:"Leandro Lucarella" wroteTrue, but the example after that statement is: a = b ~ c[0..0]; whereas foo is doing: a ~= b; which does not necessarily have to make a copy, it could reallocate 'a'. An in fact it does. It either reallocates if it can do so in place or creates a new copy. That plus the fact that the callers array length never changes means you're right, it's deterministic. ReganFrank Benoit, el 27 de noviembre a las 11:01 me escribiste:It is very deterministic actually. From http://www.digitalmars.com/d/arrays.html "Concatenation always creates a copy of its operands, even if one of the operands is a 0 length array"Regan Heath schrieb:I think you are missing an important point here: string concatenation is a fairly common case where is really obscure to figure out if the undelying pointer gets changed or not. When a user writes pbuffer ~= "a"; it's not very intuitive to expect a realocation and pbuffer.ptr change. This could lead to some hard to find bugs, because of the lack of explicitness and non-determinism (so to speak) where pbuffer ~= "a"; could lead or not to reallocation (or the fact that pbuffer[0] = 'a' will survive the local function and concatenation *may* survive or may not).Walter Bright wrote:You missed a semicolon, so it does not compile :) Realloc does not destroy the original buffer. So your foo just make a modified copy, that is not visible for the caller. buffer will stay unchanged.Regan Heath wrote:Yes, but the underlying memory is reallocated so buffer no longer points to valid memory, right? Reganvoid foo(char[] pbuffer) { //assume this causes reallocation //assume there is no more space in place pbuffer ~= "a"; } void main() { char[] buffer = "test".dup; foo(buffer); buffer[0] = 'a' //crash } Right?No. foo() modifies its copy of pbuffer, which is not the same as buffer.
Nov 27 2007
Regan Heath wrote:Walter Bright wrote:No, a new copy is made. The old one is left alone.Regan Heath wrote:Yes, but the underlying memory is reallocated so buffer no longer points to valid memory, right?void foo(char[] pbuffer) { //assume this causes reallocation //assume there is no more space in place pbuffer ~= "a"; } void main() { char[] buffer = "test".dup; foo(buffer); buffer[0] = 'a' //crash } Right?No. foo() modifies its copy of pbuffer, which is not the same as buffer.
Nov 27 2007
Walter Bright wrote:Regan Heath wrote:So we'll have pass by value for arrays? Nifty. Seanvoid foo(char[] pbuffer) { //assume this causes reallocation //assume there is no more space in place pbuffer ~= "a"; } void main() { char[] buffer = "test".dup; foo(buffer); buffer[0] = 'a' //crash } Right?No. foo() modifies its copy of pbuffer, which is not the same as buffer.
Nov 27 2007
Sean Kelly wrote:Walter Bright wrote:Arrgh! There are two things here, the length/ptr, and the array contents. The former is passed by value.Regan Heath wrote:So we'll have pass by value for arrays? Nifty.void foo(char[] pbuffer) { //assume this causes reallocation //assume there is no more space in place pbuffer ~= "a"; } void main() { char[] buffer = "test".dup; foo(buffer); buffer[0] = 'a' //crash } Right?No. foo() modifies its copy of pbuffer, which is not the same as buffer.
Nov 27 2007
Walter Bright wrote:Sean Kelly wrote:Oops! I totally misunderstood. This is yet another reminder of why I try to avoid posting so early in the morning. One of these days the lesson will sink in. SeanWalter Bright wrote:Arrgh! There are two things here, the length/ptr, and the array contents. The former is passed by value.Regan Heath wrote:So we'll have pass by value for arrays? Nifty.void foo(char[] pbuffer) { //assume this causes reallocation //assume there is no more space in place pbuffer ~= "a"; } void main() { char[] buffer = "test".dup; foo(buffer); buffer[0] = 'a' //crash } Right?No. foo() modifies its copy of pbuffer, which is not the same as buffer.
Nov 27 2007
Walter Bright wrote:Derek Parnell wrote:Well, it might make sense with a moving GC, I suppose; which we won't have anyway, as long as we have void[] or malloc, and I think I wouldn't want to miss those. regards, frank[...] How would I specify that I have a buffer of bytes and I can't change its location but I can change its contents?You can't. A good question would be what would be the purpose of such?
Nov 26 2007
Walter Bright wrote:Derek Parnell wrote:I like it! Simple, yet it does what it needs to do.On Mon, 26 Nov 2007 14:11:25 -0800, Walter Bright wrote:It's just ignored.Jason House wrote:Is the keyword in this context now a syntax error?Walter Bright Wrote:I don't remember the details of that, but the nutshell version is: 1) no more final for variablesDenton Cockburn wrote:How about documentation of how const will work. Is this essentially what was originally posted in the "const is broken" thread? Or are there new surprises in store for us?Any update on the status of the const/invariant changes?Yes, it's about done.Const and invariant are transitive. C++ const is not transitive, leading to programmers establishing a *convention* for transitive const. But it being an unenforced convention means it is not reliable.2) no more 'head const' or 'tail const', it's all just 'const'Does that mean that if X is const then neither the bits in X and the bits referenced by X can be modified (though the X symbol)?Right.3) ditto (2) for invariantDoes that mean that if X is invariant then neither the bits in X and the bits referenced by X can be modified by anything?Yes, transitive const applies downwards, not upwards.It should be working as one would intuitively expect it to.If the answer is 'yes' to the couple of questions above ... (a) is there a form of the syntax that allows 'X' to be modified but not what it references?(b) is there a form that prevents 'X' from being modified but allows what it references to be modified?No. There is no language typing support for 'logical const' (i.e. const structures with mutable members). Many C++ people have argued passionately for logical const, but I have become strongly convinced that the notion is fatally flawed.
Nov 26 2007
Walter Bright wrote:Many C++ people have argued passionately for logical const, but I have become strongly convinced that the notion is fatally flawed.How about a constant/immutable object that refers to and uses (but does not contain) a mutable object? That's rather a common need, and it would be a shame not to be able to declare some object as being unchanging simply because it changes other objects' states, or to have to pass references to those other objects in to functions instead of holding them in member variables? -- James
Dec 17 2007
James Dennett wrote:Walter Bright wrote:But the compiler needs to assume that every reference could be an owned reference since it doesn't know who you consider to be the "owner". --bbMany C++ people have argued passionately for logical const, but I have become strongly convinced that the notion is fatally flawed.How about a constant/immutable object that refers to and uses (but does not contain) a mutable object? That's rather a common need, and it would be a shame not to be able to declare some object as being unchanging simply because it changes other objects' states, or to have to pass references to those other objects in to functions instead of holding them in member variables?
Dec 17 2007
Bill Baxter Wrote:James Dennett wrote:Is it really about ownership? That tends to imply to me that this would affect the garbage collector. I think most posts on the topic look for exceptions to the transitive const rule. i.e. where a pointer/class reference can point to some non-const data. I don't fully appreciate the trouble having something like this would cause the compiler. For parallelization of invariant objects, it seems about as bad as using a global variable.Walter Bright wrote:But the compiler needs to assume that every reference could be an owned reference since it doesn't know who you consider to be the "owner".Many C++ people have argued passionately for logical const, but I have become strongly convinced that the notion is fatally flawed.How about a constant/immutable object that refers to and uses (but does not contain) a mutable object? That's rather a common need, and it would be a shame not to be able to declare some object as being unchanging simply because it changes other objects' states, or to have to pass references to those other objects in to functions instead of holding them in member variables?
Dec 17 2007
Jason House wrote:Bill Baxter Wrote:More about "containment", but that implies ownership, and D does not directly model containment as it uses reference semantics for class types.James Dennett wrote:Is it really about ownership?Walter Bright wrote:But the compiler needs to assume that every reference could be an owned reference since it doesn't know who you consider to be the "owner".Many C++ people have argued passionately for logical const, but I have become strongly convinced that the notion is fatally flawed.How about a constant/immutable object that refers to and uses (but does not contain) a mutable object? That's rather a common need, and it would be a shame not to be able to declare some object as being unchanging simply because it changes other objects' states, or to have to pass references to those other objects in to functions instead of holding them in member variables?That tends to imply to me that this would affect the garbage collector.I don't think so.I think most posts on the topic look for exceptions to the transitive const rule. i.e. where a pointer/class reference can point to some non-const data.No "looking for" such exceptions: merely pointing out that they arise naturally in *designs* which take account of mutability, and hoping for tools which allow us to express natural designs to the compiler in a way that allows it to help to verify that the code does what our design calls for.I don't fully appreciate the trouble having something like this would cause the compiler. For parallelization of invariant objects, it seems about as bad as using a global variable.Not so different. There really are different forces at work here: from an implementor's perspective, "transitive const" is a much more convenient beast. From a software designer's view, it's a rather blunt tool compared to C++'s const. It might or might not be a pragmatic trade-off, but I think the battle for a const which is as designer-friendly as C++'s has been lost already. -- James
Dec 17 2007
Walter, please, explain us, why you don't post any thoughts on important language features like const? Why you don't tell us about concepts you want to change in constness? I think it will be very useful to discuss important features with community, before those will be implemented. As you can see, consts and invariants was not successful, i think, because it has not been discussed on conceptual stage...Denton Cockburn wrote:Any update on the status of the const/invariant changes?Yes, it's about done.I'm using D 2.0 in some things, and would hate to learn to do it X way, only to have it changed on me.While the semantic changes are extensive, I've found to my surprise that little has to change in source code that uses const.
Nov 26 2007
On Mon, 26 Nov 2007 23:43:21 +0300, Victor Tyurin wrote: Well, we did discuss const/final/invariant quite a bit before it was actually implemented. I do agree though that we should be able to talk about it, even if we do not play a role in the decision making. Discussing these things helps gain us more in-depth understanding, such that we are better prepared to adjust to the changes.Walter, please, explain us, why you don't post any thoughts on important language features like const? Why you don't tell us about concepts you want to change in constness? I think it will be very useful to discuss important features with community, before those will be implemented. As you can see, consts and invariants was not successful, i think, because it has not been discussed on conceptual stage...Denton Cockburn wrote:Any update on the status of the const/invariant changes?Yes, it's about done.I'm using D 2.0 in some things, and would hate to learn to do it X way, only to have it changed on me.While the semantic changes are extensive, I've found to my surprise that little has to change in source code that uses const.
Nov 26 2007
On Mon, 26 Nov 2007 11:32:44 -0800, Walter Bright wrote:Denton Cockburn wrote:Any update on the status of the const/invariant changes?While the semantic changes are extensive, I've found to my surprise that little has to change in source code that uses const.Prior to releasing the new version, will you tell us what the semantic changes are? It would be useful to know the paradigm, and to discuss it, in order to be fully 'aware' before we start making any source code changes for it. -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
Nov 26 2007
Denton Cockburn wrote:Any update on the status of the const/invariant changes? I'm using D 2.0 in some things, and would hate to learn to do it X way, only to have it changed on me.You can get a preview of the new way things are going to look by browsing the latest source of Phobos from dsource. I didn't spend too much looking through the changes, but it looked like D is going to be switching to the C++ style of flagging 'this' as const by putting 'const' at the end of the function signature rather than the beginning. --bb
Nov 26 2007
Bill Baxter wrote:Denton Cockburn wrote:At the beginning will still work for function types. The at the end option is there for those who are building complex type declarations.Any update on the status of the const/invariant changes? I'm using D 2.0 in some things, and would hate to learn to do it X way, only to have it changed on me.You can get a preview of the new way things are going to look by browsing the latest source of Phobos from dsource. I didn't spend too much looking through the changes, but it looked like D is going to be switching to the C++ style of flagging 'this' as const by putting 'const' at the end of the function signature rather than the beginning.
Nov 26 2007
Walter Bright schrieb:Bill Baxter wrote:Denton Cockburn wrote:At the beginning will still work for function types. The at the end option is there for those who are building complex type declarations.Any update on the status of the const/invariant changes? I'm using D 2.0 in some things, and would hate to learn to do it X way, only to have it changed on me.You can get a preview of the new way things are going to look by browsing the latest source of Phobos from dsource. I didn't spend too much looking through the changes, but it looked like D is going to be switching to the C++ style of flagging 'this' as const by putting 'const' at the end of the function signature rather than the beginning.
Nov 26 2007
Walter Bright schrieb:Bill Baxter wrote:honestly i would prefer just one single way of writing things. allowing multiple ways makes it less simple to understand external code for beginners. this is one thing i like about java that there hardly exist multiple ways to formulate the same piece of code.Denton Cockburn wrote:At the beginning will still work for function types. The at the end option is there for those who are building complex type declarations.Any update on the status of the const/invariant changes? I'm using D 2.0 in some things, and would hate to learn to do it X way, only to have it changed on me.You can get a preview of the new way things are going to look by browsing the latest source of Phobos from dsource. I didn't spend too much looking through the changes, but it looked like D is going to be switching to the C++ style of flagging 'this' as const by putting 'const' at the end of the function signature rather than the beginning.
Nov 26 2007
On 2007-11-26 18:20:18 -0500, Extrawurst <spam extrawurst.org> said:I second that: the language should help make code consistent. I don't really care which syntax is kept in the language, but in my opinion Walter should decide on one, not two. Allowing both seems like a compromise to make C++ switchers happy by permitting const at the end of a member function (as in C++), but I think it just makes the differences about const even more subtle and thus harder to learn to that group. Or is there another rationale I'm missing for having the two syntaxes? -- Michel Fortin michel.fortin michelf.com http://michelf.com/honestly i would prefer just one single way of writing things. allowing multiple ways makes it less simple to understand external code for beginners. this is one thing i like about java that there hardly exist multiple ways to formulate the same piece of code.I didn't spend too much looking through the changes, but it looked like D is going to be switching to the C++ style of flagging 'this' as const by putting 'const' at the end of the function signature rather than the beginning.At the beginning will still work for function types. The at the end option is there for those who are building complex type declarations.
Nov 27 2007
Michel Fortin wrote:On 2007-11-26 18:20:18 -0500, Extrawurst <spam extrawurst.org> said:I agree. I don't get why we need two ways to express it. What's the benefit of writing const out in front? --bbI second that: the language should help make code consistent. I don't really care which syntax is kept in the language, but in my opinion Walter should decide on one, not two. Allowing both seems like a compromise to make C++ switchers happy by permitting const at the end of a member function (as in C++), but I think it just makes the differences about const even more subtle and thus harder to learn to that group. Or is there another rationale I'm missing for having the two syntaxes?honestly i would prefer just one single way of writing things. allowing multiple ways makes it less simple to understand external code for beginners. this is one thing i like about java that there hardly exist multiple ways to formulate the same piece of code.I didn't spend too much looking through the changes, but it looked like D is going to be switching to the C++ style of flagging 'this' as const by putting 'const' at the end of the function signature rather than the beginning.At the beginning will still work for function types. The at the end option is there for those who are building complex type declarations.
Nov 27 2007
Bill Baxter wrote:I agree. I don't get why we need two ways to express it. What's the benefit of writing const out in front?1. It's semantically consistent. 2. It enables you to 'group' const member functions: const { int foo(); int bar(); } this cleans up things nicely when you have a number of member functions. Contrast this with how the same code looks in C++.
Nov 27 2007
On 11/27/07, Walter Bright <newshound1 digitalmars.com> wrote:Bill Baxter wrote:Oh, well if you put it like that, I have to agree with you! :-) The question then becomes, why do we need const at the back?I agree. I don't get why we need two ways to express it. What's the benefit of writing const out in front?1. It's semantically consistent. 2. It enables you to 'group' const member functions: const { int foo(); int bar(); }
Nov 27 2007
On Tue, 27 Nov 2007 13:59:47 -0500, Walter Bright <newshound1 digitalmars.com> wrote:2. It enables you to 'group' const member functions: const { int foo(); int bar(); } this cleans up things nicely when you have a number of member functions. Contrast this with how the same code looks in C++.The above could be the same as: int foo() const; int bar() const; and this apply to the return type: const int foo(); const int bar(); When grouping with : or { } it applies to the actual named declarations it encloses; but if const is applied before the return type, precedence (the juxtaposition) dictates association with the return type. This is what I would assume.
Nov 27 2007
On 11/27/07, Chris Miller <chris dprogramming.com> wrote:but if const is applied before the return type, precedence (the juxtaposition) dictates association with the return type. This is what I would assume.It's what I would assume too. That's what the "principle of least surprise" would lead one to expect. But we'd both be wrong.
Nov 27 2007
Chris Miller wrote:When grouping with : or { } it applies to the actual named declarations it encloses; but if const is applied before the return type, precedence (the juxtaposition) dictates association with the return type. This is what I would assume.Think about const as applying to the item being declared. Here, foo is being declared, so const applies to the foo. Not its return type. It would also completely break the consistency of storage classes if: const: const { } const meant different things.
Nov 27 2007
Walter Bright wrote:Chris Miller wrote:But const on a function isn't really a storage class. It's a type specifier on an implicit parameter. Although being able to wrap a bunch of functions in const{ } may be neat, there's no particular reason to expect that you should be able to do that based on what it actually is. Personally I'm not too wild about big storage class blocks in a class. I think it quickly makes the code hard to read. Consider: public: const: private: // am I still const here? how do I turn off const now? I just don't see the ability to say const{ ... } as a big win at all. The real annoyance with C++ const is the redundant methods in both const and non-const flavors. That's the thing to target for elimination. Here's another thought about syntax for specifying const this: in methods, make it optional to put a 'this' as a first argument. So int foo(int x) {...} becomes just a shorthand for the explicit version: int foo(this, int x) {...} Then it's obvoious that you'd write the const version as int foo(const this, int x) {...} It's sort of a halfway between explicit 'this' like in Python, and fully implicit 'this' like in C++. Doesn't do anything for the const{ ... } syntax, but I don't really see that syntax as a big win, anyway. It's really never bothered me in C++. Usually in fact I think const and non-const functions end up being more or less interleaved if you write a bunch of typical getThis(); setThis(); getThat(); setThat(); methods. Having a run of functions that are all const isn't all that common. Also const{...} does nothing to eliminate repeated consts used on other parameters besides 'this'. Consider your typical big-value-type struct where you have bunches of functions taking const references like opAdd(ref const typeof(this) other_one) {...} you still have to type all those 'const's. --bbWhen grouping with : or { } it applies to the actual named declarations it encloses; but if const is applied before the return type, precedence (the juxtaposition) dictates association with the return type. This is what I would assume.Think about const as applying to the item being declared. Here, foo is being declared, so const applies to the foo. Not its return type. It would also completely break the consistency of storage classes if: const: const { } const meant different things.
Nov 27 2007
Bill Baxter wrote:Walter Bright wrote:Only because you say it is. Pretend we don't have the current C-style function declaration syntax for a minute. The example would become: const int function() foo = () { ... }; const int function() bar = () { ... }; So one would naturally expect this to work: const { int function() foo = () { ... }; int function() bar = () { ... }; } const really *is* a storage class, even for functions. Really, I could say that const is delicious when barbecued if I decided to redefine it to mean "chicken;" you can say anything you want when you change the question. ;)Chris Miller wrote:But const on a function isn't really a storage class. It's a type specifier on an implicit parameter.When grouping with : or { } it applies to the actual named declarations it encloses; but if const is applied before the return type, precedence (the juxtaposition) dictates association with the return type. This is what I would assume.Think about const as applying to the item being declared. Here, foo is being declared, so const applies to the foo. Not its return type. It would also completely break the consistency of storage classes if: const: const { } const meant different things.Although being able to wrap a bunch of functions in const{ } may be neat, there's no particular reason to expect that you should be able to do that based on what it actually is.Well, if you extend that logic, there's no reason to expect this to work: writefln("Hi!"); After all, we don't really have letters in a computer! All we have are numbers. And even those are really just fixed-length sequences of logic values. So clearly, we shouldn't have int, we should have logic[32]. Except we don't have arrays, either, which makes this somewhat inconvient... You've got to draw the abstraction line *somewhere.* You're correct in saying that it's not obvious that you should be able to group by const when you think of a member function in terms of its implementation. But if you think of functions as values just like ints or floats (or indeed as some special kind of function that magically knows what "this" means,) then it makes perfect sense.Personally I'm not too wild about big storage class blocks in a class. I think it quickly makes the code hard to read. Consider: public: const: private: // am I still const here? how do I turn off const now?That's a separate issue, and doesn't really factor into this discussion. Again, this is a personal style issue. I love this because it lets me just go "and the rest is private." All of my classes are strictly divided into the public interface, followed by "private:" and the private interface. I could tag every single private thing as being "private," but then it all turns into spaghetti, and I lose the ability to see clear delineations in the source. Six of one, half-dozen of the other. :)I just don't see the ability to say const{ ... } as a big win at all. The real annoyance with C++ const is the redundant methods in both const and non-const flavors. That's the thing to target for elimination.I really have to agree with you here. The presence of the 'return' storage class is interesting... perhaps something similar could be done to factor out the common parts of const/non-const members?Here's another thought about syntax for specifying const this: in methods, make it optional to put a 'this' as a first argument. So int foo(int x) {...} becomes just a shorthand for the explicit version: int foo(this, int x) {...} Then it's obvoious that you'd write the const version as int foo(const this, int x) {...} It's sort of a halfway between explicit 'this' like in Python, and fully implicit 'this' like in C++.Personally, I'm not too hot on this one. It looks too much like type extensions. I mean, from the "one way to do things" POV, if you can do that, why do we even have methods in class bodies at all? You yourself said earlier: "I don't get why we need two ways to express it." So by your own reasoning, we should abandon the existing member function syntax entirely, since it would become redundant. I know a lot of people who hold very... emphatic... opinions on Python's use of 'self'. Heck, AFAIK, Guido's removing it from Python 3000. Again, this is also inconsistent with everything else you can apply const to. I don't get why we need different ways of talking about functions and everything else.Doesn't do anything for the const{ ... } syntax, but I don't really see that syntax as a big win, anyway. It's really never bothered me in C++. Usually in fact I think const and non-const functions end up being more or less interleaved if you write a bunch of typical getThis(); setThis(); getThat(); setThat(); methods. Having a run of functions that are all const isn't all that common.Can't really comment since I'm waiting for the D const stuff to come out so I can play with it. I can see it being useful for anything that has clearly delineated const and non-const interfaces. Again, I think this is an issue of how you personally like to organise things. As a side note, one of the truly terrible things about code is that we have to choose exactly one way of structuring things. We can either interleave definitions, or do them in blocks. Deeply nest modules, or shallowly nest them. Pity we can't just click a header and re-sort our code. :)Also const{...} does nothing to eliminate repeated consts used on other parameters besides 'this'. Consider your typical big-value-type struct where you have bunches of functions taking const references like opAdd(ref const typeof(this) other_one) {...} you still have to type all those 'const's.True, but then this is the only storage class I can think of that *can* apply to function arguments at all. Not surprising that no simple, general way of solving this has presented itself, considering the problem didn't exist until now.--bb-- Daniel
Nov 27 2007
Daniel Keep wrote:Bill Baxter wrote:Maybe I'm missing something here, but what exactly are you thinking you're making const there? My understanding is that const applied to a method of a class means 'this' is const. Const applied to a bare function or a static method has no useful interpretation AFAIK. If I'm wrong please correct me. I haven't been using D2.0 so I don't know the nuances of how const works there.Walter Bright wrote:Only because you say it is. Pretend we don't have the current C-style function declaration syntax for a minute. The example would become: const int function() foo = () { ... }; const int function() bar = () { ... }; So one would naturally expect this to work: const { int function() foo = () { ... }; int function() bar = () { ... }; } const really *is* a storage class, even for functions.Chris Miller wrote:But const on a function isn't really a storage class. It's a type specifier on an implicit parameter.When grouping with : or { } it applies to the actual named declarations it encloses; but if const is applied before the return type, precedence (the juxtaposition) dictates association with the return type. This is what I would assume.Think about const as applying to the item being declared. Here, foo is being declared, so const applies to the foo. Not its return type. It would also completely break the consistency of storage classes if: const: const { } const meant different things.Really, I could say that const is delicious when barbecued if I decided to redefine it to mean "chicken;" you can say anything you want when you change the question. ;)I wasn't intending to change the question. Your response sounds to me like you're the one changing the question ... to something about tasty chicken. So please explain again.My point was that there is no precedent in the language for something like const applying blockwise. It's a really different kind of beast from private/public/protected or from version(){}. That's not to say we can't define it to behave the same way just that there's no entity in the language that's exactly like it that *compels* us to say const{...} must be allowed in the name of consistency. If you want to say the usage looks kinda like "private" so lets let "const" syntax work similarly, then fine, it's a valid argument. But it's also a valid argument to say that const is different enough that it shouldn't work the same way as private/public. In fact there is no 'unconst' so as far as I know you won't be able to do 'const:' like you can do 'private:'. Unless Walter declares some syntax for it like '!const'.Although being able to wrap a bunch of functions in const{ } may be neat, there's no particular reason to expect that you should be able to do that based on what it actually is.Well, if you extend that logic, there's no reason to expect this to work: writefln("Hi!");After all, we don't really have letters in a computer! All we have are numbers. And even those are really just fixed-length sequences of logic values. So clearly, we shouldn't have int, we should have logic[32]. Except we don't have arrays, either, which makes this somewhat inconvient... You've got to draw the abstraction line *somewhere.* You're correct in saying that it's not obvious that you should be able to group by const when you think of a member function in terms of its implementation. But if you think of functions as values just like ints or floats (or indeed as some special kind of function that magically knows what "this" means,) then it makes perfect sense.How does it make sense to think of a function as being const without considering the actual thing you're promising won't change? A mere function has no 'state' of its own so there's nothing to make constant. Its the data referred to by the function that the function is promising not to change....Ok there's part of my confusion right there -- I was under the impression that const on arguments was classified as a type constructor, not a storage class. But anyway the fact that it is unique in that respect just goes back to underscore my point that nothing compels us to go out of our way to treat it like every other storage class. Maybe even calling it a storage class is misleading to begin with. Maybe it is sufficiently different that it deserves a different moniker. --bbAlso const{...} does nothing to eliminate repeated consts used on other parameters besides 'this'. Consider your typical big-value-type struct where you have bunches of functions taking const references like opAdd(ref const typeof(this) other_one) {...} you still have to type all those 'const's.True, but then this is the only storage class I can think of that *can* apply to function arguments at all.
Nov 27 2007
Bill Baxter wrote:Daniel Keep wrote:No, you're not missing anything. Personally, I blame brain-slippage. You're correct; the above only vaguely makes sense, and certainly doesn't mean what I implied it means.Bill Baxter wrote:Maybe I'm missing something here, but what exactly are you thinking you're making const there? My understanding is that const applied to a method of a class means 'this' is const. Const applied to a bare function or a static method has no useful interpretation AFAIK. If I'm wrong please correct me. I haven't been using D2.0 so I don't know the nuances of how const works there....Only because you say it is. Pretend we don't have the current C-style function declaration syntax for a minute. The example would become: const int function() foo = () { ... }; const int function() bar = () { ... }; So one would naturally expect this to work: const { int function() foo = () { ... }; int function() bar = () { ... }; } const really *is* a storage class, even for functions.Again, I apologise for the snafu on my part. Honestly, I can't imagine where I got that from. Except for the chicken; I happen to rather like chicken, and it was the tastiest metaphor I could come up with.Really, I could say that const is delicious when barbecued if I decided to redefine it to mean "chicken;" you can say anything you want when you change the question. ;)I wasn't intending to change the question. Your response sounds to me like you're the one changing the question ... to something about tasty chicken. So please explain again.Well, what about static? You can apply that to blocks, AFAIK. Same thing with extern(X) decorators. As for the uncost, I was under the impression that 'thing:' blocks did not stack. That is, private: static: int foo; // foo is public and static I would expect the same thing to apply in this case; it would be like static in that I can't think of any inverse for it.My point was that there is no precedent in the language for something like const applying blockwise. It's a really different kind of beast from private/public/protected or from version(){}. That's not to say we can't define it to behave the same way just that there's no entity in the language that's exactly like it that *compels* us to say const{...} must be allowed in the name of consistency. If you want to say the usage looks kinda like "private" so lets let "const" syntax work similarly, then fine, it's a valid argument. But it's also a valid argument to say that const is different enough that it shouldn't work the same way as private/public. In fact there is no 'unconst' so as far as I know you won't be able to do 'const:' like you can do 'private:'. Unless Walter declares some syntax for it like '!const'.Although being able to wrap a bunch of functions in const{ } may be neat, there's no particular reason to expect that you should be able to do that based on what it actually is.Well, if you extend that logic, there's no reason to expect this to work: writefln("Hi!");I think this is where I got my thoughts mixed up. Taking a member function, the only piece of state this has that you could conceivably 'const'ify is the 'this' pointer. Although, I admit this is a rather tenuous link.After all, we don't really have letters in a computer! All we have are numbers. And even those are really just fixed-length sequences of logic values. So clearly, we shouldn't have int, we should have logic[32]. Except we don't have arrays, either, which makes this somewhat inconvient... You've got to draw the abstraction line *somewhere.* You're correct in saying that it's not obvious that you should be able to group by const when you think of a member function in terms of its implementation. But if you think of functions as values just like ints or floats (or indeed as some special kind of function that magically knows what "this" means,) then it makes perfect sense.How does it make sense to think of a function as being const without considering the actual thing you're promising won't change? A mere function has no 'state' of its own so there's nothing to make constant. Its the data referred to by the function that the function is promising not to change.The way I've understood it is that const is both a type constructor *and* a storage class. When invoked with parenthesis, it's a type constructor. When invoked without, it's a storage class that happens to apply the type constructor to whatever the type of the declaration is. In any case, I retract my argument above since it's clear not even I am sure what I'm saying. :P I still *feel* that putting the 'const' out the front is OK, although I now cannot give you a rational argument for it. -- Daniel "this is why I don't post on the NG much..."...Ok there's part of my confusion right there -- I was under the impression that const on arguments was classified as a type constructor, not a storage class. But anyway the fact that it is unique in that respect just goes back to underscore my point that nothing compels us to go out of our way to treat it like every other storage class. Maybe even calling it a storage class is misleading to begin with. Maybe it is sufficiently different that it deserves a different moniker. --bbAlso const{...} does nothing to eliminate repeated consts used on other parameters besides 'this'. Consider your typical big-value-type struct where you have bunches of functions taking const references like opAdd(ref const typeof(this) other_one) {...} you still have to type all those 'const's.True, but then this is the only storage class I can think of that *can* apply to function arguments at all.
Nov 27 2007
Daniel Keep wrote:The way I've understood it is that const is both a type constructor *and* a storage class.That's right. It's a floor wax *and* a dessert topping!When invoked with parenthesis, it's a type constructor. When invoked without, it's a storage class that happens to apply the type constructor to whatever the type of the declaration is.That's right, too.
Nov 27 2007
On Nov 28, 2007 4:29 AM, Walter Bright <newshound1 digitalmars.com> wrote:Daniel Keep wrote:I think we do all understand this. The problem is that it took us (...well, me at least...) a long time before I /did/ grok it. I had to ask questions on this newsgroup, and have it all explained to me. This overuse of the word "const" is, in fact, one of the things which caused complaints that the D2.007 const is "a mess". Yes - the head const/tail const distinction caused confusion, but in my book, the double-use of the the words "const" and "invariant" in situations where it's not always obvious which meaning is intended, was equally part of the confusion, and therefore falls into the category of that which you have to sort out. Similar problems would arise if you made "static" or "private" into a type constructor. I've no idea what such things might mean, but just hypothetically, if one could define a type static(int) or private(char)[], then /exactly the same/ confusion would arise. It is coincidence that "const int x;" means the same thing as "const(int) x;" It is not so helpful that the analogy does not extend to "const int f()" meaning the same things as "const(int) f()". I believe it is a mistake for the same keyword, "const", to double up with both meanings. (And the same logic applies to "invariant"). Since there is a clear need for the "const" type-constructor, we should keep that. But there is less of a need for "const" as an attribute. Perhaps we don't need it at all there. As has been suggested previously, attributes of "const(this)" and "invariant(this)" can be used to define const/invariant functions. "static" is largely taking over from "const" in meaning "available at compile time", and soon we'll have "macro" to fill out the remaining duties. If we ditch const-as-an-attribute altogether, it would require only minor changes to get code compiling again: e.g. const int[] table = [ 1, 2, 3, 4 ]; becomes const(int[]) table = [ 1, 2, 3, 4 ]; or perhaps even static int[] table = [ 1, 2, 3, 4 ]; All confusion is immediately eliminated, and everyone's happy. Even the compiler! After all, it will still have a context-free grammar and be fast to compile. It's a big win-win for everyone. The only downside I can see is that it would break code, but since it would break it in an easily fixable way, I don't see that as a big deal.The way I've understood it is that const is both a type constructor *and* a storage class.That's right. It's a floor wax *and* a dessert topping!When invoked with parenthesis, it's a type constructor. When invoked without, it's a storage class that happens to apply the type constructor to whatever the type of the declaration is.That's right, too.
Nov 27 2007
Janice Caron wrote:If we ditch const-as-an-attribute altogether, it would require only minor changes to get code compiling again: e.g. const int[] table = [ 1, 2, 3, 4 ]; becomes const(int[]) table = [ 1, 2, 3, 4 ];I think it would be pretty hard to give up: const x = 3; Also, C++ has const as both a storage class and a type constructor, and yes, they have subtly different meanings. This doesn't seem to cause any major problems.
Nov 28 2007
On Nov 28, 2007 10:10 AM, Walter Bright <newshound1 digitalmars.com> wrote:I think it would be pretty hard to give up: const x = 3;Why? It would just turn into something else, like const(int) x = 3; static x = 3; macro x = 3; ...or something. I mean, you get to invent the syntax.Also, C++ has const as both a storage class and a type constructor, and yes, they have subtly different meanings. This doesn't seem to cause any major problems.That's because C++ behaves as expected. If I declare const int * f(); then I get a function which returns a pointer to const int, /not/ a const member function which returns a pointer to mutable int. I other words, in C++, the const adheres to the return type, not the function's "this" pointer. The D behaviour is drastically different and vastly unintuitive. I don't know whether this is syntactically considered to be a storage class or a type constructor in C++, but really, it's irrelevant to me. What matters is the principle of least surprise. It should do what we expect it to do, and not something else.
Nov 28 2007
Janice Caron wrote:On Nov 28, 2007 10:10 AM, Walter Bright <newshound1 digitalmars.com> wrote:Because those alternatives all look terrible. And frankly, how could anyone be confused about what: const x = 3; means? I can't understand throwing that out to improve clarity?I think it would be pretty hard to give up: const x = 3;Why? It would just turn into something else, like const(int) x = 3; static x = 3; macro x = 3;What is expected, or what you are *used* to? Let me put it another way, can you explain the difference between C++ const storage class and C++ const type constructors? There's a big semantic difference.Also, C++ has const as both a storage class and a type constructor, and yes, they have subtly different meanings. This doesn't seem to cause any major problems.That's because C++ behaves as expected. If I declare const int * f(); then I get a function which returns a pointer to const int, /not/ a const member function which returns a pointer to mutable int.I other words, in C++, the const adheres to the return type, not the function's "this" pointer. The D behaviour is drastically different and vastly unintuitive.D's const storage class applies to the declaration. That makes intuitive sense, although it is different from C++.I don't know whether this is syntactically considered to be a storage class or a type constructor in C++, but really, it's irrelevant to me. What matters is the principle of least surprise. It should do what we expect it to do, and not something else.Every other storage class applies to the declaration, why should const be completely different?
Nov 28 2007
Walter Bright wrote:Janice Caron wrote:On Nov 28, 2007 10:10 AM, Walter Bright <newshound1 digitalmars.com> wrote:We're talking here about methods, right? And you're saying if we can do this: static int[] func() { } then why shouldn't we be able to do this: const int[] func() { } ?? (Just trying to make sure I understand your point.) Acutally, when comparing side by side with "static", that starts to sound reasonable. Both are mucking with func's implicit 'this' paramter (static eliminates it, const makes it const). The big difference is just that 'static int[]' as a return value makes no sense, so there's only one way to read it, but "returns a const int[]" is a logical way to mis-read the const version, especially for C++ converts. One workaround for people who find that confusing would be to reiterate the protection: const public int[] func() {} Which is not much more verbose than const(this) int[] func() { } So I guess I can see people getting used to this. So the question again becomes why allow the at-the-end syntax too? Isn't one syntax enough? Is it just because you want to avoid const const int[] func() {} ? --bbI other words, in C++, the const adheres to the return type, not the function's "this" pointer. The D behaviour is drastically different and vastly unintuitive.D's const storage class applies to the declaration. That makes intuitive sense, although it is different from C++.I don't know whether this is syntactically considered to be a storage class or a type constructor in C++, but really, it's irrelevant to me. What matters is the principle of least surprise. It should do what we expect it to do, and not something else.Every other storage class applies to the declaration, why should const be completely different?
Nov 28 2007
On 11/28/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:Acutally, when comparing side by side with "static", that starts to sound reasonable. Both are mucking with func's implicit 'this' paramter (static eliminates it, const makes it const).Put like that, it does make sense. But then, at global scope, a static function is one which does compile-time function execution. Both const and static change their meaning when applied to functions inside a class. I can live with the existing const-at-the-front syntax. It's not what I'd prefer, but I can live with it. But if we do keep it, please let's ditch const-at-the-back. Two different syntaxes is even more confusing than what we have now. I mean, I can't write int f() static; now, can I?
Nov 28 2007
Bill Baxter wrote:Walter Bright wrote:And you can do that.Every other storage class applies to the declaration, why should const be completely different?We're talking here about methods, right? And you're saying if we can do this: static int[] func() { } then why shouldn't we be able to do this: const int[] func() { } ??The big difference is just that 'static int[]' as a return value makes no sense, so there's only one way to read it, but "returns a const int[]" is a logical way to mis-read the const version, especially for C++ converts.Ok, let's assume C++ is intuitive, consistent, and logical. Given: const int *p; what makes more logical, intuitive sense? 1) p is a non-constant pointer to const int? 2) p is a const pointer to a non-const int? 3) p is a const pointer to a const int? I doubt you'll get a consistent answer from programmers who aren't already very used to the wacky C++ semantics.One workaround for people who find that confusing would be to reiterate the protection: const public int[] func() {} Which is not much more verbose than const(this) int[] func() { }I doubt people will be confused by it for more than 5 minutes, and then it will make sense. I find the D version of const much more intuitive, from a logical, consistency point of view, than the C++ one.So I guess I can see people getting used to this. So the question again becomes why allow the at-the-end syntax too? Isn't one syntax enough?It's a good question. Note that D allows both C-style and D-style array declarations. It makes it easier to convert C code over to D code.
Nov 28 2007
Walter Bright wrote:Bill Baxter wrote:Ok, but that seems to differ from your default position on other topics. Usually I see you saying we should do things to not confuse C++ coders. "If it looks like C++ it should behave like C++" is the impression I've gotten in the past. But maybe you're gaining enough confidence in D these days that you're not as concerned about that any more. :-) ... So can we talk about the fall-through default in switch statements again? :-)Walter Bright wrote:And you can do that.Every other storage class applies to the declaration, why should const be completely different?We're talking here about methods, right? And you're saying if we can do this: static int[] func() { } then why shouldn't we be able to do this: const int[] func() { } ??The big difference is just that 'static int[]' as a return value makes no sense, so there's only one way to read it, but "returns a const int[]" is a logical way to mis-read the const version, especially for C++ converts.Ok, let's assume C++ is intuitive, consistent, and logical. Given: const int *p; what makes more logical, intuitive sense? 1) p is a non-constant pointer to const int? 2) p is a const pointer to a non-const int? 3) p is a const pointer to a const int? I doubt you'll get a consistent answer from programmers who aren't already very used to the wacky C++ semantics.One workaround for people who find that confusing would be to reiterate the protection: const public int[] func() {} Which is not much more verbose than const(this) int[] func() { }I doubt people will be confused by it for more than 5 minutes, and then it will make sense. I find the D version of const much more intuitive, from a logical, consistency point of view, than the C++ one.And the only commentary I've heard on that feature from D users has been negative. There could be a "silent majority" in favor of it, but I doubt it.So I guess I can see people getting used to this. So the question again becomes why allow the at-the-end syntax too? Isn't one syntax enough?It's a good question. Note that D allows both C-style and D-style array declarations.It makes it easier to convert C code over to D code.So you're making this at-the-end-const special case for no other reason than to make it easier to convert C++ code? As someone who converted a 15K-line C++ library, I don't think that this one thing will help much. At least not for someone translating manually. Perhaps it would help an automatic translator. But I doubt it. "Move const-after-parameters to const-before-declaration" would be a relatively straightforward conversion rule to implement. Much easier than the "convert-struct-with-inheritance-to-something-else" rule. :-) --bb
Nov 28 2007
Bill Baxter wrote:Ok, but that seems to differ from your default position on other topics. Usually I see you saying we should do things to not confuse C++ coders. "If it looks like C++ it should behave like C++" is the impression I've gotten in the past. But maybe you're gaining enough confidence in D these days that you're not as concerned about that any more. :-) ... So can we talk about the fall-through default in switch statements again? :-)No, because to break things in a way that results in an error message is ok, but breaking them so things silently behave differently is not ok.And the only commentary I've heard on that feature from D users has been negative. There could be a "silent majority" in favor of it, but I doubt it.But I've seen converted code that used it.
Nov 28 2007
Walter Bright wrote:But I've seen converted code that used it.Having second thoughts, I suppose that some people might be really thankful for this feature. Me being not one of them is probably not much of an argument, I agree! :) regards, frank
Nov 28 2007
Walter Bright wrote:Bill Baxter wrote:Doesn't const int func(); break things in a way that might not caught by a compiler?Ok, but that seems to differ from your default position on other topics. Usually I see you saying we should do things to not confuse C++ coders. "If it looks like C++ it should behave like C++" is the impression I've gotten in the past. But maybe you're gaining enough confidence in D these days that you're not as concerned about that any more. :-) ... So can we talk about the fall-through default in switch statements again? :-)No, because to break things in a way that results in an error message is ok, but breaking them so things silently behave differently is not ok.That doesn't mean they consciously used it, or that they would mind changing it if it were pointed out to them. Heck I might even be using it in OpenMesh/D. But that's just laziness. If someone points out to me where I am using it, I will change it. If the compiler pointed out to me that I was using it, I would change it. Don't know if I'm like everyone there. But there is also the issue with C style function pointer declarations. Wasn't that allowed for a while then eventually gotten rid of in favor of "just one way to do it"? --bbAnd the only commentary I've heard on that feature from D users has been negative. There could be a "silent majority" in favor of it, but I doubt it.But I've seen converted code that used it.
Nov 28 2007
Bill Baxter wrote:But there is also the issue with C style function pointer declarations. Wasn't that allowed for a while then eventually gotten rid of in favor of "just one way to do it"?It's still there. Check phobos/internal/object.d :-) Sean
Nov 28 2007
Bill Baxter wrote:Doesn't const int func(); break things in a way that might not caught by a compiler?I can't think of a way.The C way is still supported.That doesn't mean they consciously used it, or that they would mind changing it if it were pointed out to them. Heck I might even be using it in OpenMesh/D. But that's just laziness. If someone points out to me where I am using it, I will change it. If the compiler pointed out to me that I was using it, I would change it. Don't know if I'm like everyone there. But there is also the issue with C style function pointer declarations. Wasn't that allowed for a while then eventually gotten rid of in favor of "just one way to do it"?And the only commentary I've heard on that feature from D users has been negative. There could be a "silent majority" in favor of it, but I doubt it.But I've seen converted code that used it.
Nov 28 2007
"Walter Bright" <newshound1 digitalmars.com> wrote in message news:filh8n$5ce$1 digitalmars.com...The C way is still supported.As is uglily demonstrated by DDoc and all compiler error messages involving function pointers.
Nov 29 2007
On 11/28/07, Walter Bright <newshound1 digitalmars.com> wrote:what makes more logical, intuitive sense? 1) p is a non-constant pointer to const int? 2) p is a const pointer to a non-const int? 3) p is a const pointer to a const int? I doubt you'll get a consistent answer from programmers who aren't already very used to the wacky C++ semantics.You are of course completely correct about that, Walter. However, nobody here is claiming that C++ got it right. Rather, we're saying that D /should/ get it right. Just because C++ is confusing, doesn't mean D has to be confusing too.
Nov 28 2007
Janice Caron wrote:You are of course completely correct about that, Walter. However, nobody here is claiming that C++ got it right. Rather, we're saying that D /should/ get it right. Just because C++ is confusing, doesn't mean D has to be confusing too.But much of the justifications used here are that C++ is intuitive. It isn't, it's just what you're used to. Also, there are many uses to which const is put. There's no way any useful definition of it will be 100% pure and consistent. For example, const x = 3; is inconsistent. But it is far too darned useful to sacrifice for some notion of perfection.
Nov 28 2007
Walter Bright wrote:Janice Caron wrote:I don't think it's that C++ is intuitive: it's that it's not as hard for people to grok, in this area, as D. (And let's admit that C++'s declaration syntax is one of worst things about C++, so D should be able to avoid that criticism.) -- JamesYou are of course completely correct about that, Walter. However, nobody here is claiming that C++ got it right. Rather, we're saying that D /should/ get it right. Just because C++ is confusing, doesn't mean D has to be confusing too.But much of the justifications used here are that C++ is intuitive. It isn't, it's just what you're used to.
Dec 17 2007
Walter Bright wrote:Ok, let's assume C++ is intuitive, consistent, and logical. Given: const int *p; what makes more logical, intuitive sense? 1) p is a non-constant pointer to const int? 2) p is a const pointer to a non-const int? 3) p is a const pointer to a const int? I doubt you'll get a consistent answer from programmers who aren't already very used to the wacky C++ semantics.Okay, you can take me as one sample, I suck at C++! Hah! I haven't even followed the thread very closely... =) I'd expect... hmmm... option 1: I'd think *p is an int (p being the pointer), it's just not an int but a const int. But I really couldn't be sure, and would probably look it up... Btw. wouldn't it be "const int* p" in D? Just changing the spacing makes me re-think my answer! Argh!I doubt people will be confused by it for more than 5 minutes, and then it will make sense. I find the D version of const much more intuitive, from a logical, consistency point of view, than the C++ one.I guess now I'll have to go and look up both!Actually, when it comes to array declaration style, I wouldn't care if the old style was dropped in D. The new one works fine (for me), and there are some good arguments for having just OWTDI. regards, frankSo I guess I can see people getting used to this. So the question again becomes why allow the at-the-end syntax too? Isn't one syntax enough?It's a good question. Note that D allows both C-style and D-style array declarations. It makes it easier to convert C code over to D code.
Nov 28 2007
0ffh wrote:Actually, when it comes to array declaration style, I wouldn't care if the old style was dropped in D. The new one works fine (for me), and there are some good arguments for having just OWTDI.For new code, there isn't much point to using the C style array declarations. But when you're translating a big chunk of C code, it's a time and bug saver. Converting the array declarations from C style to D style is surprisingly error prone and rather tedious. It cannot be automated with simple string editors.
Nov 28 2007
Walter Bright escribió:0ffh wrote:But it could be automated with a smarter "editor". In fact, I'm willing to add an option in Descent to do it if there is interest. The outline view already show declarations that way, so it's just a matter of "writing down" the code with a simple visitor. Of course, it still can't be done with simple string editors, so if you don't have an IDE keeping the C syntax is still time saver.Actually, when it comes to array declaration style, I wouldn't care if the old style was dropped in D. The new one works fine (for me), and there are some good arguments for having just OWTDI.For new code, there isn't much point to using the C style array declarations. But when you're translating a big chunk of C code, it's a time and bug saver. Converting the array declarations from C style to D style is surprisingly error prone and rather tedious. It cannot be automated with simple string editors.
Nov 28 2007
Walter Bright wrote:0ffh wrote:I agree, it is useful to help port C/C++ code to D.Actually, when it comes to array declaration style, I wouldn't care if the old style was dropped in D. The new one works fine (for me), and there are some good arguments for having just OWTDI.For new code, there isn't much point to using the C style array declarations. But when you're translating a big chunk of C code, it's a time and bug saver. Converting the array declarations from C style to D style is surprisingly error prone and rather tedious. It cannot be automated with simple string editors.
Nov 28 2007
On 11/28/07, Walter Bright <newshound1 digitalmars.com> wrote:Because those alternatives all look terrible. And frankly, how could anyone be confused about what: const x = 3; means? I can't understand throwing that out to improve clarity?You have misunderstood me. The suggestion is that "const" shall not be an attribute. This does not rule out allowing "const x = 3;" being a legal statement, it only means you have to change the grammar of a declaration in order to allow it.Let me put it another way, can you explain the difference between C++ const storage class and C++ const type constructors? There's a big semantic difference.I just checked the grammar of C++, and C++'s list of storage-class-specifiers doesn't actually include "const", so I think neither of us is using the term correctly. However, in C++, if a statement such as "const int x = 3;" occurs at global scope, then x is invariant. We can call that a storage class if you want. The similar looking, but drastically different statement "const int * p = whatever;" uses const as a type constructor, equivalent to D's const(int). In C++, this can also be written as "int const * p" (a style I prefer as it now reads from right to left as "p is a pointer to const int"). As far as member functions go, the C++ const storage class cannot be applied to them because it makes no sense (because a member function cannot be declared at global scope. By definition, it is always in the scope of the enclosing class). Thus, when I write (in C++) class A { int f() const; } The word "const" is /not/ acting as a "storage class". Instead, it tells us that "this" is const within f.D's const storage class applies to the declaration. That makes intuitive sense, although it is different from C++.But what makes no sense is the very notion of a function (as opposed to its "this" pointer) being const. All functions are, by definition, invariant. That is, the bytes of machine code which are executed, may not be changed by any part of the program. If you take the address of those bytes of machine code, that's a pointer to invariant. The RAM utilitised during that function's execution (the stack, or the member variables, or both) are part of that function's context, and we care whether or not the function is allowed to modify those variables in the course of its execution. Thus, the kind of constness we are talking about is the constness of the function's context, not of the function itself. You can call that a "storage class" if you want, but it means something very different from a variable declared at global scope. So what you're saying as that the meaning of the word "const" changes from place to place, depending on what it applies to. For instance class A { const { int x; int f(); } } This /in fact/ means that the class A has a member variable called x, which is a const(int), and a function f, which does not modify anything through this. Those are two totally different meanings of "const"Every other storage class applies to the declaration, why should const be completely different?Functions can't have storage classes. The notion of a function being anything other than invariant ... well, it just doesn't happen in today's world (though I do remember the old days of self-modifying code). The storage class of a function's /context/ - that's a different thing, and needs a different syntax. ...and that's all I'm suggesting really. Let the syntax be const(this), instead of merely const. (I can't claim credit for that idea. Someone else came up with that one. I just like it lots). That makes it clear that we're talking about the storage class of the function's context, and explicitly names that context as the function's "this". My objection to the existing syntax is more or less solely that const int f(); does not declare that f returns a const int, and I think that all newcomers to D will find that /hugely/ confusing.
Nov 28 2007
Janice Caron wrote:On 11/28/07, Walter Bright <newshound1 digitalmars.com> wrote:Janice, what are your thoughts about how the 'static' attribute fits into that. I was thinking largely the way you were, but 'static' seems to be another example of a "storage class" that doesn't change anything about the function per-se, but rather it's parameters. Just like the const "storage class", it mucks with the hidden "this" parameter. If you're going to allow "static" to modify the 'this' parameter by sticking it out in front of a function, then it seems you should allow const the same courtesy. --bbBecause those alternatives all look terrible. And frankly, how could anyone be confused about what: const x = 3; means? I can't understand throwing that out to improve clarity?You have misunderstood me. The suggestion is that "const" shall not be an attribute. This does not rule out allowing "const x = 3;" being a legal statement, it only means you have to change the grammar of a declaration in order to allow it.Let me put it another way, can you explain the difference between C++ const storage class and C++ const type constructors? There's a big semantic difference.I just checked the grammar of C++, and C++'s list of storage-class-specifiers doesn't actually include "const", so I think neither of us is using the term correctly. However, in C++, if a statement such as "const int x = 3;" occurs at global scope, then x is invariant. We can call that a storage class if you want. The similar looking, but drastically different statement "const int * p = whatever;" uses const as a type constructor, equivalent to D's const(int). In C++, this can also be written as "int const * p" (a style I prefer as it now reads from right to left as "p is a pointer to const int"). As far as member functions go, the C++ const storage class cannot be applied to them because it makes no sense (because a member function cannot be declared at global scope. By definition, it is always in the scope of the enclosing class). Thus, when I write (in C++) class A { int f() const; } The word "const" is /not/ acting as a "storage class". Instead, it tells us that "this" is const within f.D's const storage class applies to the declaration. That makes intuitive sense, although it is different from C++.But what makes no sense is the very notion of a function (as opposed to its "this" pointer) being const. All functions are, by definition, invariant. That is, the bytes of machine code which are executed, may not be changed by any part of the program. If you take the address of those bytes of machine code, that's a pointer to invariant. The RAM utilitised during that function's execution (the stack, or the member variables, or both) are part of that function's context, and we care whether or not the function is allowed to modify those variables in the course of its execution. Thus, the kind of constness we are talking about is the constness of the function's context, not of the function itself. You can call that a "storage class" if you want, but it means something very different from a variable declared at global scope.
Nov 28 2007
On 11/28/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:Janice, what are your thoughts about how the 'static' attribute fits into that. I was thinking largely the way you were, but 'static' seems to be another example of a "storage class" that doesn't change anything about the function per-se, but rather it's parameters. Just like the const "storage class", it mucks with the hidden "this" parameter. If you're going to allow "static" to modify the 'this' parameter by sticking it out in front of a function, then it seems you should allow const the same courtesy.I have to agree with you. But as you mentioned earlier, "static" can't be a type constructor, so it never leads to (apparent) ambiguity. It's that (apparent) ambiguity that makes me feel uneasy. If the precence rules were changed such that in a declaration statement like const int f(); the const bound to the int, rather than to the f, then I don't see how it would break anything else. The only thing is that you'd then need a different way to say that "this" is const within f. Whether that's const-at-the-back, like in C++, or const(this), or whatever, it would be necessary, because you have to have /some/ way of saying that. Consider: const int delegate(int) dg; What is const here? Under Walter's rules, dg, which is a delegate (actually a pointer to those machine code bytes, and a pointer to some function's context) is what we're claiming is const, so dg could never be assigned, except in the declaration itself. How do we declare a delegate to a const (that is, whose this is const) function? I don't know. Can it even be done?
Nov 28 2007
On Wed, 28 Nov 2007 20:33:20 +0000, Janice Caron wrote:My objection to the existing syntax is more or less solely that const int f(); does not declare that f returns a const int, and I think that all newcomers to D will find that /hugely/ confusing.The simple fact is that const type funcname(); looks ambiguous. It LOOKS like it could mean either that funcname() returns a const type OR that funcname() is const but returns a non-const type. Once you know the rules you can workout what is intended, but it is not as intuitive as you might like it to be. Will it really be so hard to provide syntax that is not so ambiguous? Also, what is the syntax for a const function that returns a const type? const (const type) funcname(); ???? const const type funcname(); ??? const (const type funcname)(); ??? const (const type funcname()); ??? Walter, your efforts to achieve simplicity are being thwarted by the results being simplistic. The D programming language has way too much keyword overloading to make it an easy language to learn and remember. -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
Nov 28 2007
Derek Parnell wrote:The simple fact is that const type funcname(); looks ambiguous. It LOOKS like it could mean either that funcname() returns a const type OR that funcname() is const but returns a non-const type. Once you know the rules you can workout what is intended, but it is not as intuitive as you might like it to be. Will it really be so hard to provide syntax that is not so ambiguous? Also, what is the syntax for a const function that returns a const type?The rule for constructing a const type is to enclose that type in parentheses, so: const const(type) funcname(); or: const(type) funcname()const; or: const { const(type) funcname(); }Walter, your efforts to achieve simplicity are being thwarted by the results being simplistic.I think it is thwarted by people believing it is far more complicated than it actually is. For example, in the above case, you have to use const twice, because there are two different things in the same declaration you want to be const. Forget about const as a storage class for the moment, and just think of const as a type constructor. To make a type const, const(T) and it will all follow from there.
Nov 28 2007
Walter Bright wrote:Derek Parnell wrote:That's a good way to remember it. If we get used to seeing and writing cosnt(T) everywhere C++ would have said "const T", then it should become natural to see const int foo() as a "const(this)" rather than returing const int. --bbThe simple fact is that const type funcname(); looks ambiguous. It LOOKS like it could mean either that funcname() returns a const type OR that funcname() is const but returns a non-const type. Once you know the rules you can workout what is intended, but it is not as intuitive as you might like it to be. Will it really be so hard to provide syntax that is not so ambiguous? Also, what is the syntax for a const function that returns a const type?The rule for constructing a const type is to enclose that type in parentheses, so: const const(type) funcname(); or: const(type) funcname()const; or: const { const(type) funcname(); }Walter, your efforts to achieve simplicity are being thwarted by the results being simplistic.I think it is thwarted by people believing it is far more complicated than it actually is. For example, in the above case, you have to use const twice, because there are two different things in the same declaration you want to be const. Forget about const as a storage class for the moment, and just think of const as a type constructor. To make a type const, const(T) and it will all follow from there.
Nov 28 2007
Janice Caron wrote:I just checked the grammar of C++, and C++'s list of storage-class-specifiers doesn't actually include "const", so I think neither of us is using the term correctly.The C++ spec doesn't call const a storage class explicitly, but it is clear in saying what the "linkage" of a const declaration is, which is what the storage class is. It also fits in the grammar with storage classes, i.e. you can do things like: const static int x = 3;The similar looking, but drastically different statement "const int *So I infer you agree that C++ is not consistent or intuitive <g>.p = whatever;" uses const as a type constructor, equivalent to D's const(int). In C++, this can also be written as "int const * p" (a style I prefer as it now reads from right to left as "p is a pointer to const int").As far as member functions go, the C++ const storage class cannot be applied to them because it makes no sense (because a member function cannot be declared at global scope. By definition, it is always in the scope of the enclosing class). Thus, when I write (in C++) class A { int f() const; } The word "const" is /not/ acting as a "storage class". Instead, it tells us that "this" is const within f.I think this over analyzes things, and it looks for consistency where there simply cannot be (and there aren't in C++, either).D's const storage class applies to the declaration. That makes intuitive sense, although it is different from C++.But what makes no sense is the very notion of a function (as opposed to its "this" pointer) being const. All functions are, by definition, invariant. That is, the bytes of machine code which are executed, may not be changed by any part of the program. If you take the address of those bytes of machine code, that's a pointer to invariant. The RAM utilitised during that function's execution (the stack, or the member variables, or both) are part of that function's context, and we care whether or not the function is allowed to modify those variables in the course of its execution. Thus, the kind of constness we are talking about is the constness of the function's context, not of the function itself. You can call that a "storage class" if you want, but it means something very different from a variable declared at global scope. So what you're saying as that the meaning of the word "const" changes from place to place, depending on what it applies to. For instance class A { const { int x; int f(); } } This /in fact/ means that the class A has a member variable called x, which is a const(int), and a function f, which does not modify anything through this. Those are two totally different meanings of "const"Every other storage class applies to the declaration, why should const be completely different?Functions can't have storage classes. The notion of a function being anything other than invariant ... well, it just doesn't happen in today's world (though I do remember the old days of self-modifying code). The storage class of a function's /context/ - that's a different thing, and needs a different syntax....and that's all I'm suggesting really. Let the syntax be const(this), instead of merely const. (I can't claim credit for that idea. Someone else came up with that one. I just like it lots). That makes it clear that we're talking about the storage class of the function's context, and explicitly names that context as the function's "this".I don't think it adds anything but extra typing.My objection to the existing syntax is more or less solely that const int f(); does not declare that f returns a const int, and I think that all newcomers to D will find that /hugely/ confusing.Const is different in D than in C++, and it will take some getting used to for refugees from C++. Anyone who expects it to behave exactly like C++ will have difficulty. But if they spend a little time looking at it and give it a chance, I think they'll find that it is more consistent, intuitive, and usable than C++ const. Just remember, the const storage class applies to the declaration, not the type, and it will make sense.
Nov 28 2007
On 11/28/07, Walter Bright <newshound1 digitalmars.com> wrote:So I infer you agree that C++ is not consistent or intuitive <g>.Of course I agree with that. How could I not!? :-)I don't think it adds anything but extra typing.It adds the ability to parse the declaration differently, so that const binds to the type, not the identifier, so while const(this) int[] f(); is extra typing compared with the existing syntax, it would free up the existing syntax to mean const(int[]) f()Const is different in D than in C++, and it will take some getting used to for refugees from C++. Anyone who expects it to behave exactly like C++ will have difficulty. But if they spend a little time looking at it and give it a chance, I think they'll find that it is more consistent, intuitive, and usable than C++ const.So, how do I declare dg to be a delegate which can call a const member function? Would it be (const int delegate()) dg; ?
Nov 28 2007
Janice Caron wrote:So, how do I declare dg to be a delegate which can call a const member function? Would it be (const int delegate()) dg; ?No. Storage class are not type constructors. To use const as a type constructor, use (): const(int delegate()) dg;
Nov 28 2007
Walter Bright wrote:Janice Caron wrote:Here's a class that compiles fine and will probably mostly work. class Klass { this() { array.length = 10; } const int elem(int i) { return array[i]; } int[] array; } But someday when someone tries to call elem() with a const Klass it will fail to compile. Also in case anyone else wasn't sure, this is how you declare the common idiom of const method returning a const reference in the latest D2.008: const const(int*) get_elem_ptr(int i) {...} Without the parens it gives "Redundant storage class". (However declaring it "public public public" still does not create an error...) Also const int* get_elem_ptr(int i) fails to compile because it tries to return a mutable pointer from a const method. So that case is ok, but the one in Klass above seems like trouble brewing to me. --bbMy objection to the existing syntax is more or less solely that const int f(); does not declare that f returns a const int, and I think that all newcomers to D will find that /hugely/ confusing.Const is different in D than in C++, and it will take some getting used to for refugees from C++. Anyone who expects it to behave exactly like C++ will have difficulty. But if they spend a little time looking at it and give it a chance, I think they'll find that it is more consistent, intuitive, and usable than C++ const. Just remember, the const storage class applies to the declaration, not the type, and it will make sense.
Nov 28 2007
Bill Baxter wrote:Here's a class that compiles fine and will probably mostly work. class Klass { this() { array.length = 10; } const int elem(int i) { return array[i]; } int[] array; } But someday when someone tries to call elem() with a const Klass it will fail to compile.Yes. So where's the problem? Also, why would one want to return a "const int"? It doesn't make much sense.Also in case anyone else wasn't sure, this is how you declare the common idiom of const method returning a const reference in the latest D2.008: const const(int*) get_elem_ptr(int i) {...} Without the parens it gives "Redundant storage class". (However declaring it "public public public" still does not create an error...) Also const int* get_elem_ptr(int i) fails to compile because it tries to return a mutable pointer from a const method. So that case is ok, but the one in Klass above seems like trouble brewing to me. --bb
Nov 28 2007
Walter Bright wrote:Bill Baxter wrote:Doh. Good point. It doesn't make much sense returning a const int. I started with the function "const int*elem()", found out that didn't compile, and tweaked it so it would compile. But I forgot to double check that the resulting code still made sense. :-o --bbHere's a class that compiles fine and will probably mostly work. class Klass { this() { array.length = 10; } const int elem(int i) { return array[i]; } int[] array; } But someday when someone tries to call elem() with a const Klass it will fail to compile.Yes. So where's the problem? Also, why would one want to return a "const int"? It doesn't make much sense.
Nov 28 2007
On Thu, 29 Nov 2007 04:53:43 -0000, Bill Baxter = <dnewsgroup billbaxter.com> wrote:Walter Bright wrote:=Bill Baxter wrote:Here's a class that compiles fine and will probably mostly work. class Klass { this() { array.length =3D 10; } const int elem(int i) { return array[i]; } int[] array; } But someday when someone tries to call elem() with a const Klass it =will fail to compile.Yes. So where's the problem? Also, why would one want to return a =="const int"? It doesn't make much sense.Doh. Good point. It doesn't make much sense returning a const int. I started with the function "const int*elem()", found out that didn't =compile, and tweaked it so it would compile. But I forgot to double =check that the resulting code still made sense. :-o --bbI personally agree that const on value types in C++ is a stupid idea. Meyers recommends it (effective C++) for the following case however: T operator*(T,T) if ((a*b)=3Dc)) { //oops! instead of: if ((a*b)=3D=3Dc) { Personally I prefer to use lint to disallow assignment in boolean = expressions. There is a school that uses const value types even for builtins like int= . I am currently trying to convince people at work that it is pointless an= d = neither being const correct not just a style thing. By the way to the const(this) advocates. Though the idea looks nice on t= he = surface it isn't quite consistent. const works on type (declarations), this is a= = variable not a type. Regards, Bruce.
Nov 29 2007
Bruce Adams wrote:On Thu, 29 Nov 2007 04:53:43 -0000, Bill Baxter <dnewsgroup billbaxter.com> wrote:Oh, yeh, I do vaguely remember that one. Good point. Also for opIndex it can be used to prevent people thinking they're modifying the array when they're not: struct FakeArray { int opIndex(int i) { return i*i; } } FakeArray x; x[4]; //ok x[4]++; // oops, only increments a tmp! probably not what you meant! whereas if it returns a 'const int' the compiler will tell you you're an idiot.Walter Bright wrote:I personally agree that const on value types in C++ is a stupid idea. Meyers recommends it (effective C++) for the following case however: T operator*(T,T) if ((a*b)=c)) { //oops! instead of: if ((a*b)==c) {Bill Baxter wrote:Doh. Good point. It doesn't make much sense returning a const int. I started with the function "const int*elem()", found out that didn't compile, and tweaked it so it would compile. But I forgot to double check that the resulting code still made sense. :-o --bbHere's a class that compiles fine and will probably mostly work. class Klass { this() { array.length = 10; } const int elem(int i) { return array[i]; } int[] array; } But someday when someone tries to call elem() with a const Klass it will fail to compile.Yes. So where's the problem? Also, why would one want to return a "const int"? It doesn't make much sense.Personally I prefer to use lint to disallow assignment in boolean expressions. There is a school that uses const value types even for builtins like int. I am currently trying to convince people at work that it is pointless and neither being const correct not just a style thing.I don't see much point in decorating all your value parameters with it. But I've seen code written in that style. All it does is promise to the caller that the function won't modify something that the caller can't see anyway. Why do that?By the way to the const(this) advocates. Though the idea looks nice on the surface it isn't quite consistent. const works on type (declarations), this is a variable not a type.Ok. Let's make it "const(typeof(this))" then. :-) Actually that's why I kind of preferred my "const()" suggestion. It's applying const to the 'this' parameter which of course you can't see, because it's implicit. --bb
Nov 29 2007
Bill Baxter wrote:Bruce Adams wrote:My bad, the compiler actually catches that. But it doesn't catch it if you make opIndex return a struct with an opPostInc. And ooh another D2 bug: actually making it return a const(Strukt) crashes the compiler. --bbOn Thu, 29 Nov 2007 04:53:43 -0000, Bill Baxter <dnewsgroup billbaxter.com> wrote:Oh, yeh, I do vaguely remember that one. Good point. Also for opIndex it can be used to prevent people thinking they're modifying the array when they're not: struct FakeArray { int opIndex(int i) { return i*i; } } FakeArray x; x[4]; //ok x[4]++; // oops, only increments a tmp! probably not what you meant! whereas if it returns a 'const int' the compiler will tell you you're an idiot.Walter Bright wrote:I personally agree that const on value types in C++ is a stupid idea. Meyers recommends it (effective C++) for the following case however: T operator*(T,T) if ((a*b)=c)) { //oops! instead of: if ((a*b)==c) {Bill Baxter wrote:Doh. Good point. It doesn't make much sense returning a const int. I started with the function "const int*elem()", found out that didn't compile, and tweaked it so it would compile. But I forgot to double check that the resulting code still made sense. :-o --bbHere's a class that compiles fine and will probably mostly work. class Klass { this() { array.length = 10; } const int elem(int i) { return array[i]; } int[] array; } But someday when someone tries to call elem() with a const Klass it will fail to compile.Yes. So where's the problem? Also, why would one want to return a "const int"? It doesn't make much sense.
Nov 29 2007
On Nov 30, 2007 12:16 AM, Bruce Adams <tortoise_74 yeah.who.co.uk> wrote:By the way to the const(this) advocates. Though the idea looks nice on the surface it isn't quite consistent. const works on type (declarations), this is a variable not a type.Of course it's not consistent with existing syntax, otherwise it would already compile. const(this) is proposed /new/ syntax. In fact, I proposed extending the idea to const(lvalue), where lvalue is any lvalue known at compile time. This would allow you to do: class Outer { int outerX; class Inner { int innerX; const(outer) f(/*...*/) } } Here f promises not to modify anything accessed through outer, so any attempt to modify outerX (for example) would be picked up at compile time. Personally, I really like the idea. const(this) becomes a special case of that, and replaces const-for-member-functions very nicely.
Nov 30 2007
Bruce Adams wrote: [snip]I personally agree that const on value types in C++ is a stupid idea. Meyers recommends it (effective C++) for the following case however: T operator*(T,T) if ((a*b)=c)) { //oops! instead of: if ((a*b)==c) { Personally I prefer to use lint to disallow assignment in boolean expressions.A good compiler can do that for you too (though using lint is a fine idea to supplement even a good compiler). (Scott's advice here doesn't suit me; "do as the ints do" isThere is a school that uses const value types even for builtins like int. I am currently trying to convince people at work that it is pointless and neither being const correct not just a style thing.It's not pointless, and it's not just a style thing. It avoids defects, and it makes code clearer for those who are used to both styles. Maybe instead of setting out to convince people of something, you could set out to discover which solution really works better in practice. Using const has known advantages in expressiveness and defect elimination; apart from saving typing, what's the benefit of *not* recording the design decision that some value will not change during execution? It's a very lightweight, compile-time enforced invariant check. -- James
Dec 17 2007
James Dennett wrote:Bruce Adams wrote: [snip]I can't speak for all the cases the original poster was talking about, but const on value parameters is useless excess verbiage in my opinion. float sin(const float) { ... } Here I'm recording my design decision that my implementation of sin will not change its copy of the float argument passed in. Great. Callers just don't care. Such uses of const clutter up the interface for no good reason in my opinion. Most other uses of const on simple value types I'm ok with. --bbI personally agree that const on value types in C++ is a stupid idea. Meyers recommends it (effective C++) for the following case however: T operator*(T,T) if ((a*b)=c)) { //oops! instead of: if ((a*b)==c) { Personally I prefer to use lint to disallow assignment in boolean expressions.A good compiler can do that for you too (though using lint is a fine idea to supplement even a good compiler). (Scott's advice here doesn't suit me; "do as the ints do" isThere is a school that uses const value types even for builtins like int. I am currently trying to convince people at work that it is pointless and neither being const correct not just a style thing.It's not pointless, and it's not just a style thing. It avoids defects, and it makes code clearer for those who are used to both styles. Maybe instead of setting out to convince people of something, you could set out to discover which solution really works better in practice. Using const has known advantages in expressiveness and defect elimination; apart from saving typing, what's the benefit of *not* recording the design decision that some value will not change during execution? It's a very lightweight, compile-time enforced invariant check.
Dec 17 2007
Bill Baxter wrote:I can't speak for all the cases the original poster was talking about, but const on value parameters is useless excess verbiage in my opinion. float sin(const float) { ... } Here I'm recording my design decision that my implementation of sin will not change its copy of the float argument passed in. Great. Callers just don't care. Such uses of const clutter up the interface for no good reason in my opinion. Most other uses of const on simple value types I'm ok with.Isn't there a value in knowing the argument will never change when passing potentially large structs to functions by value? For example, calling void foo(Struct a); will in most cases mean that a copy of the passed Struct is made on the callers stack, and the address to that copy is then passed to the callee. If the compiler knew the Struct argument never changed, it could avoid making several copies for consecutive calls to such functions, and if the called function was pure, avoid making a copy at all. -- Oskar
Dec 17 2007
Oskar Linde wrote:Bill Baxter wrote:If the compiler can verify that no attempts were made to modify the struct when you label it "const" then it can also detect that no attempts were made to modify it even if you don't label it "const". And if so, it can do whatever optimization it would have done given a "const" label without burdening the developer with thinking about it. --bbI can't speak for all the cases the original poster was talking about, but const on value parameters is useless excess verbiage in my opinion. float sin(const float) { ... } Here I'm recording my design decision that my implementation of sin will not change its copy of the float argument passed in. Great. Callers just don't care. Such uses of const clutter up the interface for no good reason in my opinion. Most other uses of const on simple value types I'm ok with.Isn't there a value in knowing the argument will never change when passing potentially large structs to functions by value? For example, calling void foo(Struct a); will in most cases mean that a copy of the passed Struct is made on the callers stack, and the address to that copy is then passed to the callee. If the compiler knew the Struct argument never changed, it could avoid making several copies for consecutive calls to such functions, and if the called function was pure, avoid making a copy at all.
Dec 17 2007
Bill Baxter wrote:Oskar Linde wrote:Separate compilation means that the compiler can verify clients against the interface separately from verifying that the implementation honors the interface. The compiler need not have access to the implementation when compiling client code. -- JamesBill Baxter wrote:If the compiler can verify that no attempts were made to modify the struct when you label it "const" then it can also detect that no attempts were made to modify it even if you don't label it "const". And if so, it can do whatever optimization it would have done given a "const" label without burdening the developer with thinking about it.I can't speak for all the cases the original poster was talking about, but const on value parameters is useless excess verbiage in my opinion. float sin(const float) { ... } Here I'm recording my design decision that my implementation of sin will not change its copy of the float argument passed in. Great. Callers just don't care. Such uses of const clutter up the interface for no good reason in my opinion. Most other uses of const on simple value types I'm ok with.Isn't there a value in knowing the argument will never change when passing potentially large structs to functions by value? For example, calling void foo(Struct a); will in most cases mean that a copy of the passed Struct is made on the callers stack, and the address to that copy is then passed to the callee. If the compiler knew the Struct argument never changed, it could avoid making several copies for consecutive calls to such functions, and if the called function was pure, avoid making a copy at all.
Dec 18 2007
Bill Baxter wrote:James Dennett wrote:And you're close to the crucial point. For C++, it makes sense to write a function *definition* with top-level const as above, to avoid typos in the function which accidentally modify its copy of the argument. It means *nothing* to the caller, so the function's declaration (which is part of its interface) need not (and, for style reasons, should not) include the const -- in a non-definition, top-level const is a meaningless comment, and the compiler ignores it. -- JamesBruce Adams wrote: [snip]I can't speak for all the cases the original poster was talking about, but const on value parameters is useless excess verbiage in my opinion. float sin(const float) { ... } Here I'm recording my design decision that my implementation of sin will not change its copy of the float argument passed in. Great. Callers just don't care. Such uses of const clutter up the interface for no good reason in my opinion. Most other uses of const on simple value types I'm ok with.I personally agree that const on value types in C++ is a stupid idea. Meyers recommends it (effective C++) for the following case however: T operator*(T,T) if ((a*b)=c)) { //oops! instead of: if ((a*b)==c) { Personally I prefer to use lint to disallow assignment in boolean expressions.A good compiler can do that for you too (though using lint is a fine idea to supplement even a good compiler). (Scott's advice here doesn't suit me; "do as the ints do" isThere is a school that uses const value types even for builtins like int. I am currently trying to convince people at work that it is pointless and neither being const correct not just a style thing.It's not pointless, and it's not just a style thing. It avoids defects, and it makes code clearer for those who are used to both styles. Maybe instead of setting out to convince people of something, you could set out to discover which solution really works better in practice. Using const has known advantages in expressiveness and defect elimination; apart from saving typing, what's the benefit of *not* recording the design decision that some value will not change during execution? It's a very lightweight, compile-time enforced invariant check.
Dec 18 2007
On Mon, 17 Dec 2007 16:12:05 -0000, James Dennett <jdennett acm.org> wro= te:Bruce Adams wrote: [snip]I personally agree that const on value types in C++ is a stupid idea.=In actual fact when I sat down to check it and prove the point either wa= y I discovered that gcc in every case I could think of produces a is not a= n l-value syntax error.Meyers recommends it (effective C++) for the following case however: T operator*(T,T) if ((a*b)=3Dc)) { //oops! instead of: if ((a*b)=3D=3Dc) { Personally I prefer to use lint to disallow assignment in boolean expressions.A good compiler can do that for you too (though using lint is a fine idea to supplement even a good compiler).(Scott's advice here doesn't suit me; "do as the ints do" is=There is a school that uses const value types even for builtins like =int. I am currently trying to convince people at work that it is pointless=You misread me. I am strongly in favour of const-correctness. My point w= as about const on value returns, which do not contribute to const correctne= ss. const is about the interface contract for a function. There is no = difference between const valueType1 foobar(const valueType1) and valueType1 foobar(valueType2) valueType1 is not an l-value and therefore not assignable etc. valueType2 the situation is not quite the same but I would contend that.= . Whether or not valueType2 is modified by foobar is an implementation = detail and should not be part of the contract. You can just as easily say in the body: foobar(valueType2 bar) { const valueType2 IamConst =3D bar; ... use IamConst } or foobar(const valueType2) { valueType2 IamNotConst =3D bar; ... use IamNotConst } constness helps a little here but it affects the implementation only. Ideally I'd like the to be able to declare constness of an argument in the implementation but leave it out of the declaration. Implementation i= n = the compiler wise it would be trivial but syntactically its hard to think of somethin= g = appropriate. In D this is even weirder because you don't have separate declarations a= nd = implementations.and neither being const correct not just a style thing.It's not pointless, and it's not just a style thing. It avoids defects, and it makes code clearer for those who are used to both styles. Maybe instead of setting out to convince people of something, you could set out to discover which solution really works better in practice. Using const has known advantages in expressiveness and defect elimination; apart from saving typing, what's the benefit of *not* recording the design decision that some value will not change during execution? It's a very lightweight, compile-time enforced invariant check. -- James
Dec 17 2007
On Mon, 17 Dec 2007 19:16:34 -0000, Bruce Adams = <tortoise_74 yeah.who.co.uk> wrote:not be part of the contract. You can just as easily say in the body: foobar(valueType2 bar) { const valueType2 IamConst =3D bar; ... use IamConst } or foobar(const valueType2) { valueType2 IamNotConst =3D bar; ... use IamNotConst } constness helps a little here but it affects the implementation only. Ideally I'd like the to be able to declare constness of an argument in=the implementation but leave it out of the declaration. Implementation==in the compiler wise it would be trivial but syntactically its hard to think of =something appropriate. In D this is even weirder because you don't have separate declarations==and implementations.Actually thinking about it. In D the syntax is easier. Implement what yo= u = like in your code and your documentation, doxygen or whatever should leave the const = = out.
Dec 17 2007
Bruce Adams Wrote:const is about the interface contract for a function. There is no difference between const valueType1 foobar(const valueType1) and valueType1 foobar(valueType2) valueType1 is not an l-value and therefore not assignable etc. valueType2 the situation is not quite the same but I would contend that.. Whether or not valueType2 is modified by foobar is an implementation detail and should not be part of the contract. You can just as easily say in the body: foobar(valueType2 bar) { const valueType2 IamConst = bar; ... use IamConst } or foobar(const valueType2) { valueType2 IamNotConst = bar; ... use IamNotConst }What if I want to pass a struct by value without copying - because I only want the changed struct? (the function is SUPPOSED to modify my struct?) In fact, that's just about the only time I ever pass structs to functions - when I want to modify them, or when I want to get something out of them. Rarely ever because I want to copy them and keep both the unmodified copy and the modified one. Regards, Dan
Dec 17 2007
On Tue, 18 Dec 2007 00:06:25 -0000, Dan <murpsoft hotmail.com> wrote:What if I want to pass a struct by value without copying - because I only want the changed struct? (the function is SUPPOSED to modify my struct?) In fact, that's just about the only time I ever pass structs to functions - when I want to modify them, or when I want to get something out of them. Rarely ever because I want to copy them and keep both the unmodified copy and the modified one. Regards, DanI can imagine how to do that in assembly. Its not possible in C/C++ Can you do that in D currently? Presumably the syntax would be: foo(inout valueType bar); In C++ that would have to be done with pass by reference. But this is well off topic, it has nothing to do with constness of value types.
Dec 17 2007
Walter Bright wrote:Because those alternatives all look terrible. And frankly, how could anyone be confused about what: const x = 3; means? I can't understand throwing that out to improve clarity?Honestly, I am confused about what that means. If I define an integer constant x, don't I want a pointer to that constant to be invariant(int)*? Doesn't that mean that constants should rather be defined as: invariant x = 3; Or am I wrong? What am I missing here? I am to tired right now to reiterate my full thoughts on the keywords (and I am sure you are all very thankful for that :) ), but it still feels like the keywords are reversed: invariant === constant const === read only -- Oskar
Nov 28 2007
Oskar Linde wrote:I am to tired right now to reiterate my full thoughts on the keywords (and I am sure you are all very thankful for that :) ), but it still feels like the keywords are reversed: invariant === constant const === read onlyI can't stand the use of "invariant" as a qualifier either, but what can you do. May as well place it next to "foreach_reverse" on the shelf of horrifying semantics and move on. As long as the semantics of const correctness improve then that will have to do. Sean
Nov 28 2007
Oskar Linde wrote:Walter Bright wrote:For a basic type, the meaning of const and invariant overlap. The difference between them is when you have pointers or other references. For simple integers, you can use const or invariant.Because those alternatives all look terrible. And frankly, how could anyone be confused about what: const x = 3; means? I can't understand throwing that out to improve clarity?Honestly, I am confused about what that means. If I define an integer constant x, don't I want a pointer to that constant to be invariant(int)*? Doesn't that mean that constants should rather be defined as: invariant x = 3; Or am I wrong? What am I missing here?I am to tired right now to reiterate my full thoughts on the keywords (and I am sure you are all very thankful for that :) ), but it still feels like the keywords are reversed: invariant === constant const === read onlyWe went around this for a while. There is no word that unambiguously means "read only view" while another word meaning unambiguously "will never change". So, since C++ uses const to mean "read only view", it seemed best to leave that as it was. readonly, constant, invariant, immutable, are all synonyms.
Nov 28 2007
Walter Bright wrote:Oskar Linde wrote:Ok, but it is then unfortunate that having two constants: invariant a = 1; const b = 2; that typeof(&a) != typeof(&b). And that given those types, only one is convertible to the other. Since invariant(int)* is convertible to const(int)*, it seems to me that there is a good reason to define constants using invariant, rather than const. invariant(int)* also captures the full meaning of a pointer to constant data.Walter Bright wrote:For a basic type, the meaning of const and invariant overlap. The difference between them is when you have pointers or other references. For simple integers, you can use const or invariant.Because those alternatives all look terrible. And frankly, how could anyone be confused about what: const x = 3; means? I can't understand throwing that out to improve clarity?Honestly, I am confused about what that means. If I define an integer constant x, don't I want a pointer to that constant to be invariant(int)*? Doesn't that mean that constants should rather be defined as: invariant x = 3; Or am I wrong? What am I missing here?Thank you for this motivation. Regarding describing words, in my book the word "constant" pretty well describes something that "will never change". And just like: float means "floating point number" int means "integer" const could mean "constant" readonly could mean "read only view" It wouldn't be hard to explain or motivate. And regarding C++, it doesn't seem to me like const was originally intended to mean "read only view". I'd guess the logical evolution was 1. const as a storage class to replace #defines -> 2. pointers to const -> 3. contract const (I promise I wont change this). Should D really copy only the most unintended part of what const is from C++ and change the most intended one?I am to tired right now to reiterate my full thoughts on the keywords (and I am sure you are all very thankful for that :) ), but it still feels like the keywords are reversed: invariant === constant const === read onlyWe went around this for a while. There is no word that unambiguously means "read only view" while another word meaning unambiguously "will never change". So, since C++ uses const to mean "read only view", it seemed best to leave that as it was.readonly, constant, invariant, immutable, are all synonyms.Only for a very weak definition of synonyms, i.e. "has overlapping meanings". That doesn't mean that they can (or should) be used interchangeably. For example, you can say that secure and protected are synonyms, but if you went to climb a cliff and told people you had "protected the rope", I bet at least a few of them would be confused. :) I'm only saying that I think there is another set of keywords that have a much higher match between the dictionary meaning of the words and their semantic meaning in D. -- Oskar
Nov 29 2007
Oskar Linde wrote:Ok, but it is then unfortunate that having two constants: invariant a = 1; const b = 2; that typeof(&a) != typeof(&b).It's not that bad. Consider: int a = 1; float b = 1; They're different types, too.And regarding C++, it doesn't seem to me like const was originally intended to mean "read only view". I'd guess the logical evolution was 1. const as a storage class to replace #defines -> 2. pointers to const -> 3. contract const (I promise I wont change this). Should D really copy only the most unintended part of what const is from C++ and change the most intended one?Is it really unintended? But even so, if you have invariant, you must have const too, since everything is implicitly convertible to const, and *that* is definitely intended in C++.I'm only saying that I think there is another set of keywords that have a much higher match between the dictionary meaning of the words and their semantic meaning in D.I don't believe there is (and we looked!), and readonly isn't it. To me, readonly means ROM (burned in to read only memory chips), not read only view. I've even seen 'readonly' used in some languages to literally mean "this stuff goes into ROM".
Nov 29 2007
Walter Bright wrote:Oskar Linde wrote:Oh, really? ;p. I don't think that is much of an argument. Think of the poor new user to D: Q: How do I define constants? A: Use invariant or const. Just pick one. Q: Are they equivalent? A: No, they result in distinct types. Q: So which one should I really use? A: Invariant is better. The references to the resulting type are then implicitly convertible to the other. Q: So why is the other one called "const"? A: ...Ok, but it is then unfortunate that having two constants: invariant a = 1; const b = 2; that typeof(&a) != typeof(&b).It's not that bad. Consider: int a = 1; float b = 1; They're different types, too.No, I can't say it was unintended. Rephrased, I will instead say that the "read only view" part of const is just one part of what const is in C++. The other part is the constant storage class that I've tried to argue is, in the case of constants at least, better handled by "invariant" in D. We can probably agree that the "const" keyword was chosen as an abbreviation for "constant", and as such, it is unfortunate that it now has lost the last connection to the meaning of that word.And regarding C++, it doesn't seem to me like const was originally intended to mean "read only view". I'd guess the logical evolution was 1. const as a storage class to replace #defines -> 2. pointers to const -> 3. contract const (I promise I wont change this). Should D really copy only the most unintended part of what const is from C++ and change the most intended one?Is it really unintended? But even so, if you have invariant, you must have const too, since everything is implicitly convertible to const, and *that* is definitely intended in C++.I know you are of that view, and your strongest association with the word "readonly" is in the sense of ROM, but I do believe you are in a minority. Uses of read-only in the context of access attributes, registers and views are well established and maps very well to the current "const" keyword. I expanded those arguments in: http://www.digitalmars.com/d/archives/digitalmars/D/Const_sucks_58017.html#N58135 and http://www.digitalmars.com/d/archives/digitalmars/D/D_const_design_rationale_54725.html#N54970 But I agree that "readonly" is far from a perfect keyword. The worst thing about it is that it is a contraction of two words (albeit a quite common one, yielding 3.5 million hits on google). To summarize, I believe the arguments for the current keywords are: * readonly is out of question * following that, no better keywords have come up * invariant was already a keyword * const will be the most used form and therefore uses the most familiar keword * const has a similar meaning in C++ The only reason I keep posting about this must be because I am an incurable optimist. Or maybe I am just too stubborn to realize I've lost. Or maybe I'm just stuck at the romantic idea that the const issue could be resolved in a way that leaves const meaning constant. :P Another alternative to readonly could be to redefine the seldom used protection attribute "protected". Protected is perfect in many ways. A protected pointer or a protected slice of memory makes sense. It is a single word and has no confusing associations. Const could then be redefined to mean "constant" again. const -> protected invariant -> const The old protection attribute could be renamed: private(class), and at the same time, the package keyword could be removed and renamed private(package), with a net result of 1 less keyword than today, and no confusion about what keyword to use for defining constants. -- OskarI'm only saying that I think there is another set of keywords that have a much higher match between the dictionary meaning of the words and their semantic meaning in D.I don't believe there is (and we looked!), and readonly isn't it. To me, readonly means ROM (burned in to read only memory chips), not read only view. I've even seen 'readonly' used in some languages to literally mean "this stuff goes into ROM".
Nov 29 2007
Yes, Oskar is right in his analysis of const vs invariant declarations. And now that I think about it, it occurs to me that NOTHING IS EVER CREATED CONST. Everything that is created in D, is either created mutable, or is created invariant. All literals are invariant. Everything created using new is mutable. .dup and .idup generate mutable and invariant respectively, but there is no .cdup. And this makes perfect sense. After all, if const means "a readonly view of something", then there must be a "something" for it to be a readonly view /of/. Thus, as Oskar pointed out, a statement like const x = 3; is actually pointless. Either you want x to be mutable, or you want x to be constant. In the former case, "auto x = 3" would do the trick; in the latter case, "invariant x = 3" should work. But "const x = 3" is redundant, because nothing can modify x /anyway/. Casting away const is undefined, so we can't do that, and since we can't do that, nothing can change it - ergo, it is invariant. Thus, we should really be writing invariant x = 3; For this reason, it seems to me that "const as a storage class" makes absolutely no sense whatsoever. Const things are not stored, /ever/. Invariant things are stored (they occupy bytes of ROM or RAM somewhere); mutable things are stored (they occupy bytes of RAM somewhere), but there is really no such animal as a const "thing" - there is only "pointer to const", or "array of const", or "custom collection of const" ... and all of those things are examples of const-as-a-type-constructor, not const-as-a-storage-class. Ah, but what about functions?, I here you ask. Well, in the case of class member functions, it's the other way round: we need const, but not invariant. Further back up this thread, Bruce Adams pointed out that it makes very little sense to define a class member function as being invariant. I did respond to that pointing out that it had a /literal/ meaning in the context of the D language, but in reality, it's a nonsensical fiction. To create an invariant class instance, you'd have to do: A a = cast(invariant(A))(new A); and unless you do that, then you can never call an invariant member function. What this means is that Bruce is basically right - defining a member function to be invariant is as pointless as defining a const literal. It seems to me that in both cases /one keyword will suffice/. So why not let "const" do double-duty? That is, we keep (*) const as a storage-class (*) const as a type-constructor (*) invariant as a type-constructor and we lose (*) invariant as a storage class with the caveat that when const-as-storage-class is applied to types which require storage, it actually means invariant (but when applied to member functions it retains its existing meaning). If we were to adopt this practice then: const x = 3; auto p = &x; would result in x having type invariant(int), and p having type invariant(int)*. Since invariant can implicitly cast to const, this is guaranteed not to break anything. It would also mean that invariant x = 3; would become a compile error, since invariant would no longer be an attribute. This seems to me to be a slightly more preferable idea than Oskar's one of redefining "protected", since, under my scheme, "const" would be the keyword you'd use in practice, most of the time. You'd use it when declaring variables, when declaring member functions const, and when promising not to modify stuff. Only rarely would you need to type the more lengthy "invariant", but it would still be there (as a type-modifier only), should you need it.
Nov 29 2007
Janice Caron wrote: <snip>So why not let "const" do double-duty? That is, we keep (*) const as a storage-class (*) const as a type-constructor (*) invariant as a type-constructor and we lose (*) invariant as a storage class with the caveat that when const-as-storage-class is applied to types which require storage, it actually means invariant (but when applied to member functions it retains its existing meaning). If we were to adopt this practice then: const x = 3; auto p = &x; would result in x having type invariant(int), and p having type invariant(int)*. Since invariant can implicitly cast to const, this is guaranteed not to break anything.I think I'd rather loose: (*) const as a storage-class and make the separation between const and invariant more pronounced. There would be no need for the caveat above, however: const x = 5; would become illegal and this breaks existing valid 1.0 code. Regan
Nov 29 2007
On Nov 29, 2007 3:17 PM, Regan Heath <regan netmail.co.nz> wrote:I think I'd rather loose: (*) const as a storage-classBut if you did that, you wouldn't be able to declare const member functions. You'd have to come up with a new syntax for that, or use "invariant" in place of const (... which, come to think of it is not such a bad idea)
Nov 29 2007
Regan Heath wrote:I think I'd rather loose: (*) const as a storage-class and make the separation between const and invariant more pronounced. There would be no need for the caveat above, however: const x = 5; would become illegal and this breaks existing valid 1.0 code.This is one reason I think "const" should be used for "data that will never change" in D 2.0. It's what it is in D 1.0. The concept is simply being extended. Sean
Nov 29 2007
Invariant member functions: you argued these are unnecessary. I believe they are, for exactly the same reason as any other invariant references passed as parameters. Invariant is needed to support functional programming, better code optimization, and more reliable multithreaded code. const as storage class: Const local variables can be initialized with const types, so there is definitely a place for them: void foo(const int *p) { const q = p; } q does *not* point to an invariant. Furthermore, being able to declare const variables is necessary as they are a boundary case in writing generic code. Boundary cases need to be supported to make writing generic code easier, even if such code would be pointless if done manually. For example, the compiler doesn't disallow (0==0), even though it is pointless to write such.
Nov 29 2007
"Walter Bright" wroteInvariant member functions: you argued these are unnecessary. I believe they are, for exactly the same reason as any other invariant references passed as parameters. Invariant is needed to support functional programming, better code optimization, and more reliable multithreaded code.I believe pure functions are required to support functional programming and more reliable multithreaded code. Given that an invariant function is allowed to change global state, it cannot be assumed that it is safe to reorder invariant function calls, cache results, or call multiple invariant functions without synchronization on multiple threads. invariant as a *storage* attribute is required for pure functions and reliable multithreaded calls. However, I think invariant functions would be good for optimization, as you can keep member data in registers between calls, etc. -Steve
Nov 29 2007
On Nov 29, 2007 8:25 PM, Walter Bright <newshound1 digitalmars.com> wrote:const as storage class: Const local variables can be initialized with const types, so there is definitely a place for them: void foo(const int *p) { const q = p; } q does *not* point to an invariant.Actually is does. If you followed all the details of my previous post, you should recall that I said: "with the caveat that when const-as-storage-class is applied to types which require storage, it actually means invariant". Thus, with that caveat borne in mind, the above code actually says: void foo(invarant int * p) { invariant q = p; } I think you applied my caveat selectively! :-) However, I grant you that that is confusing, and I would be opposed to anything which is confusing, so clearly it won't fly. Unless ... we add one further rule... (*) disallow altogether both "const" and "invariant" as function parameter storage classes. This would force the writer of the function to declare void foo(const(int)* p) or void foo(const(int *) p) (although the latter is pointless since we don't really care about head-constness), instead of void foo(const int * p) and either way, the body of the function could then become auto q = p; so we'd end up with void foo(const(int)* p) { auto q = p; } which seems eminently readable to me.
Nov 30 2007
Oskar Linde wrote:Const could then be redefined to mean "constant" again. const -> protected invariant -> const The old protection attribute could be renamed: private(class), and at the same time, the package keyword could be removed and renamed private(package), with a net result of 1 less keyword than today, and no confusion about what keyword to use for defining constants.No, please, no. This breaks too many codes, and makes protected ubyte[] bitmap_data; parsed to something unexpected. apparent as discussed before. Maybe "invariant" for read-only view? :P (ouch, that's even more confusing) -- -- Kenny.
Nov 29 2007
Oskar Linde wrote:Walter Bright wrote:FWIW my naive expectation was that "invariant a = 1" would give you something you can't take the address of because it may be inlined or whatever, whereas "const b=2" I expected to be deref-able and actually live somewhere in memory. I think the reason is that I had come to understand 'invariant' as being the one that lets the compiler do sneaky optimizations and make assumptions that something really will not change ever, whereas const merely says the reference you have isn't changing but someone else might be changing it.Oskar Linde wrote:Ok, but it is then unfortunate that having two constants: invariant a = 1; const b = 2;I know you are of that view, and your strongest association with the word "readonly" is in the sense of ROM, but I do believe you are in a minority. Uses of read-only in the context of access attributes, registers and views are well established and maps very well to the current "const" keyword. I expanded those arguments in:I agree the meaning of "readonly" is perfect, (and how on earth could it mean "put this data in ROM"? It's physically impossible unless D was some kind of EPROM burning software). BUT those three extra letters over "const" do bother me. Because in function signatures it can often be repeated 5 or more times. So though probably in the minority, I'd rather have it become "ro" if it's going to change. There is some other language that uses that. I can't remember which one. But anyway I'm not holding my breath waiting for Walter to make such a change.The only reason I keep posting about this must be because I am an incurable optimist. Or maybe I am just too stubborn to realize I've lost. Or maybe I'm just stuck at the romantic idea that the const issue could be resolved in a way that leaves const meaning constant. :POr D) all of the above. :-) --bb
Nov 29 2007
Bill Baxter wrote:I agree the meaning of "readonly" is perfect, (and how on earth could it mean "put this data in ROM"? It's physically impossible unless D was some kind of EPROM burning software). BUT those three extra letters over "const" do bother me. Because in function signatures it can often be repeated 5 or more times. So though probably in the minority, I'd rather have it become "ro" if it's going to change. There is some other language that uses that. I can't remember which one.For function signatures, the "in" parameter attribute should save some typing (makes the parameters const). It is a pity const-by-default didn't work out.But anyway I'm not holding my breath waiting for Walter to make such a change.That would certainly be an unhealthy practice.I am afraid you might be right. -- OskarThe only reason I keep posting about this must be because I am an incurable optimist. Or maybe I am just too stubborn to realize I've lost. Or maybe I'm just stuck at the romantic idea that the const issue could be resolved in a way that leaves const meaning constant. :POr D) all of the above. :-)
Nov 29 2007
On Thu, 29 Nov 2007 20:31:09 -0000, Bill Baxter <dnewsgroup billbaxter.com> wrote:I agree the meaning of "readonly" is perfect, (and how on earth could it mean "put this data in ROM"? It's physically impossible unless D was some kind of EPROM burning software). BUT those three extra letters over "const" do bother me. Because in function signatures it can often be repeated 5 or more times. So though probably in the minority, I'd rather have it become "ro" if it's going to change. There is some other language that uses that. I can't remember which one.compilers are used to write firmware which gets downloaded into EEPROMs and the like. Object module formats like ELF allow allow for separate memory regions with attributes meaning "put me in rom". Embedded C/C++ compilers sometimes have extensions for this or #pragma's or special purpose linker languages. This is where readonly, ro, rodata and other terms spring up. D is I believe intended as a systems language than can replace C and C++ even in contexts like these. Because it is broad in scope like C & C++ you have the same high-level versus low-level conflicts. Ultimately its what it says in the manual that counts however bad the fit with the dictionary word. Regards, Bruce.
Nov 29 2007
Bill Baxter wrote:I agree the meaning of "readonly" is perfect, (and how on earth could it mean "put this data in ROM"? It's physically impossible unless D was some kind of EPROM burning software).You can always put these variables into virtual pages which are readonly. From the program's viewpoint, that is little different than ROM.
Nov 30 2007
Walter Bright wrote:I favor "view" but I suppose it's too common a word. "guard" seems reasonable as well, but is also probably too common. SeanI'm only saying that I think there is another set of keywords that have a much higher match between the dictionary meaning of the words and their semantic meaning in D.I don't believe there is (and we looked!), and readonly isn't it. To me, readonly means ROM (burned in to read only memory chips), not read only view. I've even seen 'readonly' used in some languages to literally mean "this stuff goes into ROM".
Nov 29 2007
On Thu, 29 Nov 2007 01:48:02 -0000, Walter Bright = <newshound1 digitalmars.com> wrote:Oskar Linde wrote:=Walter Bright wrote:Because those alternatives all look terrible. And frankly, how could=r =anyone be confused about what: const x =3D 3; means? I can't understand throwing that out to improve clarity?Honestly, I am confused about what that means. If I define an intege=constant x, don't I want a pointer to that constant to be =invariant(int)*? Doesn't that mean that constants should rather be =defined as: invariant x =3D 3; Or am I wrong? What am I missing here?For a basic type, the meaning of const and invariant overlap. The =difference between them is when you have pointers or other references.==For simple integers, you can use const or invariant.=I am to tired right now to reiterate my full thoughts on the keywords==(and I am sure you are all very thankful for that :) ), but it still =feels like the keywords are reversed: invariant =3D=3D=3D constant const =3D=3D=3D read onlyWe went around this for a while. There is no word that unambiguously =means "read only view" while another word meaning unambiguously "will ==never change". So, since C++ uses const to mean "read only view", it =seemed best to leave that as it was. readonly, constant, invariant, immutable, are all synonyms.I still like my idea of compile time contracts / type contracts. Taking the thought experiment a bit too far... Give a type T with several interfaces you could define a contract which = = says that only certain interfaces of T can be used by the function. const T is like a (compile time) contract permitting only the use of the= = read only interface. invariant T is like a (compile time) contract that asserts X' =3D=3D X a= s a = pre-condition. i.e. the value of X will not change for the duration of the function. = Practically, this is still X is not writeable anywhere it can be used when the function is = called (i.e. it is invariant). If you had some way to specify constracts like this at compile time you = = could build head constness, tail constenss, invariantness and various other -nesses = as = library code. What you are doing with const and invariant is limiting the contracts = possible to (ideally) the most useful subset of those possible and adding syntactic sugar to let y= ou = apply them to a declaration easily. Another way to view this is that the contracts specialise the types they= = apply to. This is stretching inheritance a bit as constT needs to be a T i.e. publ= ic = inheritance / isa but needs to violate its normal interface in a way more suitable to = private inheritance / is implemented in terms of class T { int foo(); int bar() const; } const T =3D class constT: private T { int bar() const =3D T::bar; } or: class constT: public T { int bar() const =3D T::bar; private: override int foo() =3D compile_time_error("illegal attempt to invoke= = non-const method"); } You could almost have const(T) as a (particularly evil) template now. Perhaps this will inspire other options? Regards, Bruce. PS You could always invent words rov and wnc - wince ;)
Nov 29 2007
"Walter Bright" wroteJanice Caron wrote:Let me reword Walter's point, as I think he didn't really get it across completely :) Let's say someone had never used C++ and it's const system. Let's say that person is a virgin coder starting to dabble in D. Let's explain how const works to him/her: to declare that a type is constant, you do: const(Type) x; to declare that a method returns a const value, you do: const(Type) f(); to declare that a method is constant, that is, it will not modify any members of a class the method resides in, you do: const Type f(); If that method returns a const type, then the method is declared as: const const(Type) f(); for compatibility with C++ and C, you can also do: const Type x; for a const type declaration, and Type f() const for a const method declaration. To someone who never used const before in another language, this isn't any less or more intuitive than the way C++ does it. It's like saying using semicolons at the end of statements is intuitive. It's just a different way of expressing what you want to the compiler. -SteveWhat is expected, or what you are *used* to? Let me put it another way, can you explain the difference between C++ const storage class and C++ const type constructors? There's a big semantic difference.Also, C++ has const as both a storage class and a type constructor, and yes, they have subtly different meanings. This doesn't seem to cause any major problems.That's because C++ behaves as expected. If I declare const int * f(); then I get a function which returns a pointer to const int, /not/ a const member function which returns a pointer to mutable int.
Nov 28 2007
On Wed, 28 Nov 2007 23:02:06 -0500, Steven Schveighoffer wrote:If that method returns a const type, then the method is declared as: const const(Type) f();To someone who never used const before in another language, this isn't any less or more intuitive than the way C++ does it. It's like saying using semicolons at the end of statements is intuitive. It's just a different way of expressing what you want to the compiler.Got it. When I see two adjacent "const" keywords I need to realize that the first const refers to the second 'thing' and the second const refers to the first 'thing'. Very intuitive. However ... what if we tried to make things unintuitive ... like having the first const refer to the first thing and the second const refer to the second const ... Nah ... on second thoughts that would only confuse people. Who'd ever work out that ... const(Type) const f(); means that the 'Type' is const and the f() is also const? -- Derek (skype: derek.j.parnell) Melbourne, Australia 29/11/2007 3:07:14 PM
Nov 28 2007
"Derek Parnell" wroteOn Wed, 28 Nov 2007 23:02:06 -0500, Steven Schveighoffer wrote:It is if you think in stacks :)If that method returns a const type, then the method is declared as: const const(Type) f();To someone who never used const before in another language, this isn't any less or more intuitive than the way C++ does it. It's like saying using semicolons at the end of statements is intuitive. It's just a different way of expressing what you want to the compiler.Got it. When I see two adjacent "const" keywords I need to realize that the first const refers to the second 'thing' and the second const refers to the first 'thing'. Very intuitive.However ... what if we tried to make things unintuitive ... like having the first const refer to the first thing and the second const refer to the second const ... Nah ... on second thoughts that would only confuse people. Who'd ever work out that ... const(Type) const f(); means that the 'Type' is const and the f() is also const?Hey, I'm not saying it's the best way :) I'm just saying it's no less or more intuitive than the C++ way: const Type f() const It's just different. I'm all for the const(this) format suggested in another branch of this thread, as I think that's the most intuitive. -Steve
Nov 28 2007
Derek Parnell wrote:On Wed, 28 Nov 2007 23:02:06 -0500, Steven Schveighoffer wrote:To make a type const, you add parens: const(T) So, to make a const function that returns a constant T: const(const(T) f()) The storage class const is just a shorthand for putting ( ) around the whole declaration.If that method returns a const type, then the method is declared as: const const(Type) f();To someone who never used const before in another language, this isn't any less or more intuitive than the way C++ does it. It's like saying using semicolons at the end of statements is intuitive. It's just a different way of expressing what you want to the compiler.Got it. When I see two adjacent "const" keywords I need to realize that the first const refers to the second 'thing' and the second const refers to the first 'thing'. Very intuitive.
Nov 28 2007
On Wed, 28 Nov 2007 21:27:35 -0800, Walter Bright wrote:To make a type const, you add parens: const(T) So, to make a const function that returns a constant T: const(const(T) f())Is this supposed to compile? I can't get it to work. For the source line ... const(const(int*) f()){} I get the message ... test.d(3): unexpected identifer 'f' in declarator test.d(3): no identifier for declarator const(int*)() -- Derek (skype: derek.j.parnell) Melbourne, Australia 29/11/2007 5:07:48 PM
Nov 28 2007
Derek Parnell wrote:Is this supposed to compile? I can't get it to work. For the source line ... const(const(int*) f()){} I get the message ... test.d(3): unexpected identifer 'f' in declarator test.d(3): no identifier for declarator const(int*)()Uh, you're right. You can't put the identifier inside a declarator.
Nov 29 2007
On Thu, 29 Nov 2007 01:06:32 -0800, Walter Bright wrote:Derek Parnell wrote:Yes, I know one can't, but I actually asked if one is supposed to able to do it. Did you intend that "const(const(int*) f()){}" should compile, even though currently it doesn't? -- Derek Parnell Melbourne, Australia skype: derek.j.parnellIs this supposed to compile? I can't get it to work. For the source line ... const(const(int*) f()){} I get the message ... test.d(3): unexpected identifer 'f' in declarator test.d(3): no identifier for declarator const(int*)()Uh, you're right. You can't put the identifier inside a declarator.
Nov 29 2007
Derek Parnell wrote:Did you intend that "const(const(int*) f()){}" should compile, even though currently it doesn't?No. I just didn't think it through.
Nov 29 2007
Steven Schveighoffer, el 28 de noviembre a las 23:02 me escribiste:"Walter Bright" wroteThis sounds right.Janice Caron wrote:Let me reword Walter's point, as I think he didn't really get it across completely :) Let's say someone had never used C++ and it's const system. Let's say that person is a virgin coder starting to dabble in D. Let's explain how const works to him/her: to declare that a type is constant, you do: const(Type) x; to declare that a method returns a const value, you do: const(Type) f(); to declare that a method is constant, that is, it will not modify any members of a class the method resides in, you do: const Type f(); If that method returns a const type, then the method is declared as: const const(Type) f();What is expected, or what you are *used* to? Let me put it another way, can you explain the difference between C++ const storage class and C++ const type constructors? There's a big semantic difference.Also, C++ has const as both a storage class and a type constructor, and yes, they have subtly different meanings. This doesn't seem to cause any major problems.That's because C++ behaves as expected. If I declare const int * f(); then I get a function which returns a pointer to const int, /not/ a const member function which returns a pointer to mutable int.for compatibility with C++ and C, you can also do: const Type x; for a const type declaration, and Type f() const for a const method declaration.This is what it's confusing. 1) Why does D need C++ compatibility? 2) Here is were all possible confusion about "what does const Type f() const means? Is in some places const Type x means const(Type) x and in other places it doesn't, it's really confusing, specially when reading code that mix styles. I think C++ compatibility should be dropped. -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- CHINO ATRAPA COTORRAS -- Crónica TV
Nov 29 2007
Leandro Lucarella wrote:Is in some places const Type x means const(Type) x and in other places it doesn't,No, const Type X always means const(Type) x, where Type is the type of the declaration.
Nov 29 2007
Walter Bright wrote:Janice Caron wrote:Shouldn't const as a storage class mean really constant, so that typeof(&x) above would be invariant(int)* instead of const(int)*? And in that case, wouldn't it be more logical if the keword "const", as a type modifier meant constant (what invariant is today), and another keyword was used for the weaker access protection... Say "readonly". *ducks* ;) -- OskarIf we ditch const-as-an-attribute altogether, it would require only minor changes to get code compiling again: e.g. const int[] table = [ 1, 2, 3, 4 ]; becomes const(int[]) table = [ 1, 2, 3, 4 ];I think it would be pretty hard to give up: const x = 3; Also, C++ has const as both a storage class and a type constructor, and yes, they have subtly different meanings. This doesn't seem to cause any major problems.
Nov 28 2007
On Nov 28, 2007 10:10 AM, Walter Bright <newshound1 digitalmars.com> wrote:I think it would be pretty hard to give up: const x = 3; Also, C++ has const as both a storage class and a type constructor, and yes, they have subtly different meanings. This doesn't seem to cause any major problems.Actually, I may have been misunderstood, so I want to be clear. There is a difference between an ATTRIBUTE and a STORAGE CLASS. C++ has storage classes, but D does not. D has attributes, but C++. They are not the same thing. The terms are not interchangeable. For example, in C++, "typedef" is (syntactically) a storage class, but it's certainly not an attribute in D. If you want to make the statement const x = 3; legal in D, it is perfectly possible to do that without making "const" an attribute. You only have to define a "const statement" or something in the grammar. Call that a "storage class" if you want, but you don't have to grant the keyword all the power of an attribute. To keep this conversation plain, let us not confuse the terms "attribute" and "storage class" again.
Nov 28 2007
Janice Caron wrote:On Nov 28, 2007 10:10 AM, Walter Bright <newshound1 digitalmars.com> wrote:Um, "const x = 3" *is* legal in D. Has been for about a year now. SeanI think it would be pretty hard to give up: const x = 3; Also, C++ has const as both a storage class and a type constructor, and yes, they have subtly different meanings. This doesn't seem to cause any major problems.Actually, I may have been misunderstood, so I want to be clear. There is a difference between an ATTRIBUTE and a STORAGE CLASS. C++ has storage classes, but D does not. D has attributes, but C++. They are not the same thing. The terms are not interchangeable. For example, in C++, "typedef" is (syntactically) a storage class, but it's certainly not an attribute in D. If you want to make the statement const x = 3; legal in D
Nov 28 2007
On 11/28/07, Sean Kelly <sean f4.ca> wrote:Um, "const x = 3" *is* legal in D. Has been for about a year now. SeanNo need for the "Um". Of course I know that, and certainly I should have said, "if you want to /keep/ [it] legal", rather than "if you want to /make/ [it] legal". My apologies for the typographical faux pas, however it is entirely unimportant in the context of this discussion.
Nov 28 2007
Janice Caron wrote:On 11/28/07, Sean Kelly <sean f4.ca> wrote:I disagree. But back to the main point. You claimed that D does not have storage classes. Could you explain this? SeanUm, "const x = 3" *is* legal in D. Has been for about a year now. SeanNo need for the "Um". Of course I know that, and certainly I should have said, "if you want to /keep/ [it] legal", rather than "if you want to /make/ [it] legal". My apologies for the typographical faux pas, however it is entirely unimportant in the context of this discussion.
Nov 28 2007
On 11/28/07, Sean Kelly <sean f4.ca> wrote:You claimed that D does not have storage classes. Could you explain this?Certainly. In the grammar of C and C++, a rule is defined called "storage-class-specifier". The "storage-class-specifier" grammar rule forms part of the rule defining the syntax of a declaration. There is no corresponding grammar element in D. The storage class specifiers in C and C++ are auto, extern, mutable, register, static and typedef. See the grammar at http://www.kuzbass.ru:8086/docs/isocpp/gram.html The closest grammar element D has is "attribute". This is defined on the web page. http://www.digitalmars.com/d/attribute.html. D attributes are deprecated, static, final, override, abstract, const, auto, scope, and various other constructs as defined on that page. Though there is overlap between C's storage classes and D's attributes, they are not completely identical, and in consequence, some analogies don't work.
Nov 28 2007
Janice Caron wrote:On 11/28/07, Sean Kelly <sean f4.ca> wrote:I think this is a distinction without a difference. D also has storage classes static, extern, etc., which work just like storage classes in C++. Syntactically (and the grammar rules for), attributes and storage classes are exactly the same.You claimed that D does not have storage classes. Could you explain this?Certainly. In the grammar of C and C++, a rule is defined called "storage-class-specifier". The "storage-class-specifier" grammar rule forms part of the rule defining the syntax of a declaration. There is no corresponding grammar element in D. The storage class specifiers in C and C++ are auto, extern, mutable, register, static and typedef. See the grammar at http://www.kuzbass.ru:8086/docs/isocpp/gram.html The closest grammar element D has is "attribute". This is defined on the web page. http://www.digitalmars.com/d/attribute.html. D attributes are deprecated, static, final, override, abstract, const, auto, scope, and various other constructs as defined on that page. Though there is overlap between C's storage classes and D's attributes, they are not completely identical, and in consequence, some analogies don't work.
Nov 28 2007
On Nov 27, 2007 9:42 PM, Bill Baxter <dnewsgroup billbaxter.com> wrote:The real annoyance with C++ const is the redundant methods in both const and non-const flavors.Make that THREE flavours in D byte[] f(byte[] b) {/*...*/} const(byte)[] f(const(byte)[] b) {/*...*/} invariant(byte)[] f(invariant(byte)[] b) {/*...*/}That's the thing to target for elimination.Absolutely agreed! My favourite proposed syntax for that is constType(byte)[] f(constType(byte)[] b) {/*...*/} "constType" is a new keyword. The idea is that the compiler generates at most three versions of the function, with "constType" replaced by "const", "invariant" or nothing at all in each case. The symbol "constType" would be available inside the body of the function too. If any of the three flavours don't compile, then it is not an error - instead, they are simply not instantiated. You don't have to invent a new keyword, of course. Any symbol will do instead of "constType", as long as it's clear what's going on, and not ambiguous - even "return". :-)
Nov 27 2007
"Janice Caron" <caron800 googlemail.com> wrote in message news:mailman.147.1196235159.2338.digitalmars-d puremagic.com...On Nov 27, 2007 9:42 PM, Bill Baxter <dnewsgroup billbaxter.com> wrote:Read the conference slides? In fact you even guessed the keyword -- "return". I think it's something like: byte[] f(return byte[] b) { /* ... */ } The return type is then dependent upon the constness of the input. It's _kind of_ like a templated function, but unlike a templated function it can be virtual.The real annoyance with C++ const is the redundant methods in both const and non-const flavors.Make that THREE flavours in D byte[] f(byte[] b) {/*...*/} const(byte)[] f(const(byte)[] b) {/*...*/} invariant(byte)[] f(invariant(byte)[] b) {/*...*/}That's the thing to target for elimination.Absolutely agreed! My favourite proposed syntax for that is constType(byte)[] f(constType(byte)[] b) {/*...*/} "constType" is a new keyword. The idea is that the compiler generates at most three versions of the function, with "constType" replaced by "const", "invariant" or nothing at all in each case. The symbol "constType" would be available inside the body of the function too. If any of the three flavours don't compile, then it is not an error - instead, they are simply not instantiated. You don't have to invent a new keyword, of course. Any symbol will do instead of "constType", as long as it's clear what's going on, and not ambiguous - even "return". :-)
Nov 28 2007
On 11/26/07, Walter Bright <newshound1 digitalmars.com> wrote:At the beginning will still work for function types. The at the end option is there for those who are building complex type declarations.andNo. "const char[] X;" and "const(char[]) X;" mean the same thing.It seems to me that the following is still ambiguous: class A { int n; } class B { const A f() { /*...*/ } } Does it mean (a) class B { const(A) f() { /*...*/ } } or does it mean (b) class B { A f() const { /*...*/ } } ? Also, is it still possible to write class C { int n; void f() invariant { /*...*/ }; } (I put the keyword at the end to avoid confusion. In D2.007, you'd write "invariant" before "void"). My interpretation of the above code is that f is being called with a hidden parameter "this" of type "invariant(C)", which means that the function can never be called, unless by an invariant instance of C (since nothing implicitly casts to invariant). Have I got that right?
Nov 26 2007
Janice Caron wrote:On 11/26/07, Walter Bright <newshound1 digitalmars.com> wrote:(b). Think of it this way: const A f() means: const (A f()) which applies the const to the function f, not A.At the beginning will still work for function types. The at the end option is there for those who are building complex type declarations.andNo. "const char[] X;" and "const(char[]) X;" mean the same thing.It seems to me that the following is still ambiguous: class A { int n; } class B { const A f() { /*...*/ } } Does it mean (a) class B { const(A) f() { /*...*/ } } or does it mean (b) class B { A f() const { /*...*/ } } ?Also, is it still possible to write class C { int n; void f() invariant { /*...*/ }; }Yes.(I put the keyword at the end to avoid confusion. In D2.007, you'd write "invariant" before "void"). My interpretation of the above code is that f is being called with a hidden parameter "this" of type "invariant(C)", which means that the function can never be called, unless by an invariant instance of C (since nothing implicitly casts to invariant). Have I got that right?Yes.
Nov 27 2007
On Nov 27, 2007 9:13 AM, Walter Bright <newshound1 digitalmars.com> wrote:Think of it this way: const A f() means: const (A f()) which applies the const to the function f, not A.Ah, but the natural interpretation of const(...) is that /everything/ inside the brackets is const. Thus, if I write const(void f(char[] b)) that "suggests" to me that b is const, since it is inside (albeit deeply inside) the const(...) brackets. But I only want f's "this" to be const, not b. Perhaps this is a case where "const at the end" creates a more helpful mneumonic?
Nov 27 2007
Janice Caron wrote:Ah, but the natural interpretation of const(...) is that /everything/ inside the brackets is const. Thus, if I write const(void f(char[] b)) that "suggests" to me that b is const, since it is inside (albeit deeply inside) the const(...) brackets.That's only if one thinks that const, when applied to a function, also influences its return type. There is no reason why transitive const should apply in this way.But I only want f's "this" to be const, not b. Perhaps this is a case where "const at the end" creates a more helpful mneumonic?It leads to awful looking code when you have a lot of them to do.
Nov 27 2007
On 11/27/07, Walter Bright <newshound1 digitalmars.com> wrote:That's only if one thinks that const, when applied to a function, also influences its return type. There is no reason why transitive const should apply in this way.I do understand. But I'm thinking of the poor programmer who hasn't unravelled all the knots yet, and wants a member function to return a const ubyte[]. Such a programmer could easily accidentally end up writing const ubyte[] f() {/*...*/} thinking (not unreasonably) that this will return a const ubyte[] ... and being completely wrong.If you're making const-at-the-end syntactically valid, then it's fair game to use it. If you don't want it used, don't make it legal. But if you /do/ make it legal, the (apparent) disambiguation it gives is, I feel, helpful. Other possible syntaxes have been suggested. Here's another one to consider: ReturnType const(functionName)(parameters...)Perhaps this is a case where "const at the end" creates a more helpful mneumonic?It leads to awful looking code when you have a lot of them to do.
Nov 27 2007
Janice Caron wrote:On 11/27/07, Walter Bright <newshound1 digitalmars.com> wrote:Since a const array cannot be implicitly cast to a non-const, he'll get a compilation error. It's the big feature of const-correctness, the code won't compile if you get it wrong.That's only if one thinks that const, when applied to a function, also influences its return type. There is no reason why transitive const should apply in this way.I do understand. But I'm thinking of the poor programmer who hasn't unravelled all the knots yet, and wants a member function to return a const ubyte[]. Such a programmer could easily accidentally end up writing const ubyte[] f() {/*...*/} thinking (not unreasonably) that this will return a const ubyte[] ... and being completely wrong.Sorry, but that's awful looking (besides looking confusingly like a template).If you're making const-at-the-end syntactically valid, then it's fair game to use it. If you don't want it used, don't make it legal. But if you /do/ make it legal, the (apparent) disambiguation it gives is, I feel, helpful. Other possible syntaxes have been suggested. Here's another one to consider: ReturnType const(functionName)(parameters...)Perhaps this is a case where "const at the end" creates a more helpful mneumonic?It leads to awful looking code when you have a lot of them to do.
Nov 27 2007
On 11/27/07, Walter Bright <newshound1 digitalmars.com> wrote:Since a const array cannot be implicitly cast to a non-const, he'll get a compilation error.Not necessarily. They might be relying on implicit cast to const in the first place. e.g. class A { const ubyte[] f() { ubyte[] b; /* initialise b */ return b; } } Here the programmer (who hasn't yet learned that "const ubyte[] f()" means "ubyte[] f() const" rather than "const(ubyte[]) f()") is assuming that when b is returned, it will be implicitly cast from ubyte[] to const ubyte[]. That assumption is wrong, but I believe the code still compiles.It's the big feature of const-correctness, the code won't compile if you get it wrong.Of course, and that's why I love it. But not all incorrect code involving const is necessarily const-incorrect. :-)I completely agree. Sorry to have mentioned it.Other possible syntaxes have been suggested. Here's another one to consider: ReturnType const(functionName)(parameters...)Sorry, but that's awful looking
Nov 27 2007
Janice Caron wrote:On 11/27/07, Walter Bright <newshound1 digitalmars.com> wrote:Sure, but the code is also not broken.Since a const array cannot be implicitly cast to a non-const, he'll get a compilation error.Not necessarily. They might be relying on implicit cast to const in the first place. e.g. class A { const ubyte[] f() { ubyte[] b; /* initialise b */ return b; } } Here the programmer (who hasn't yet learned that "const ubyte[] f()" means "ubyte[] f() const" rather than "const(ubyte[]) f()") is assuming that when b is returned, it will be implicitly cast from ubyte[] to const ubyte[]. That assumption is wrong, but I believe the code still compiles.It's the big feature of const-correctness, the code won't compile if you get it wrong.Of course, and that's why I love it. But not all incorrect code involving const is necessarily const-incorrect. :-)I completely agree. Sorry to have mentioned it.Other possible syntaxes have been suggested. Here's another one to consider: ReturnType const(functionName)(parameters...)Sorry, but that's awful looking
Nov 27 2007
On Tue, 27 Nov 2007, Walter Bright wrote:Janice Caron wrote:Also, don't forget the array vs slice changes that have been proposed in the past (page 26 of the conference presentation). That set of changes will help with this class of problem in a way that const can't. Later, BradOn 11/27/07, Walter Bright <newshound1 digitalmars.com> wrote:Sure, but the code is also not broken.Since a const array cannot be implicitly cast to a non-const, he'll get a compilation error.Not necessarily. They might be relying on implicit cast to const in the first place. e.g. class A { const ubyte[] f() { ubyte[] b; /* initialise b */ return b; } } Here the programmer (who hasn't yet learned that "const ubyte[] f()" means "ubyte[] f() const" rather than "const(ubyte[]) f()") is assuming that when b is returned, it will be implicitly cast from ubyte[] to const ubyte[]. That assumption is wrong, but I believe the code still compiles.It's the big feature of const-correctness, the code won't compile if you get it wrong.Of course, and that's why I love it. But not all incorrect code involving const is necessarily const-incorrect. :-)
Nov 27 2007
Janice Caron wrote:On Nov 27, 2007 9:13 AM, Walter Bright <newshound1 digitalmars.com> wrote:What if it were const() A f() {...} or const(this) A f() {...} ? --bbThink of it this way: const A f() means: const (A f()) which applies the const to the function f, not A.Ah, but the natural interpretation of const(...) is that /everything/ inside the brackets is const. Thus, if I write const(void f(char[] b)) that "suggests" to me that b is const, since it is inside (albeit deeply inside) the const(...) brackets. But I only want f's "this" to be const, not b. Perhaps this is a case where "const at the end" creates a more helpful mneumonic?
Nov 27 2007
Bill Baxter wrote:Janice Caron wrote:While maybe a bit of typing, I really like the const(this) form--its intent is very clear IMHO. And const(this) { int foo(); int bar(); } isn't too bad either.On Nov 27, 2007 9:13 AM, Walter Bright <newshound1 digitalmars.com> wrote:What if it were const() A f() {...} or const(this) A f() {...} ? --bbThink of it this way: const A f() means: const (A f()) which applies the const to the function f, not A.Ah, but the natural interpretation of const(...) is that /everything/ inside the brackets is const. Thus, if I write const(void f(char[] b)) that "suggests" to me that b is const, since it is inside (albeit deeply inside) the const(...) brackets. But I only want f's "this" to be const, not b. Perhaps this is a case where "const at the end" creates a more helpful mneumonic?
Nov 27 2007
On 11/27/07, David Gileadi <foo bar.com> wrote:While maybe a bit of typing, I really like the const(this) form--its intent is very clear IMHO. And const(this) { int foo(); int bar(); } isn't too bad either.For what it's worth, I completely agree with this. I think it's a fine syntax, and makes the intent very clear. It can go at the front of a function without any confusion, it's obvious what it means, and the extention to invariant(this) is equally as obvious. In the extreme unlikelihood that I have a vote, this one gets mine.
Nov 27 2007
Janice Caron wrote:On 11/27/07, David Gileadi <foo bar.com> wrote:Me too.While maybe a bit of typing, I really like the const(this) form--its intent is very clear IMHO. And const(this) { int foo(); int bar(); } isn't too bad either.For what it's worth, I completely agree with this. I think it's a fine syntax, and makes the intent very clear. It can go at the front of a function without any confusion, it's obvious what it means, and the extention to invariant(this) is equally as obvious. In the extreme unlikelihood that I have a vote, this one gets mine.
Nov 28 2007
On Nov 28, 2007 11:45 AM, Don Clugston <dac nospam.com.au> wrote:Janice Caron wrote:A thought occurs to me. (And it's a good one). Since we're considering making const(this) an attribute, why not extend it to const(identifier), for any identifier. That is, const(identifier) would syntactically be considered an attribute, and could go anywhere version(identifier) could go. It's meaning would be: within the specified scope, the named identifier shall be consisdered const (and likewise for invariant). Allowing "this" to be merely a special case of identifier, does indeed allow us to declare const member functions: const(this) void f(); as well as the abovementioned grouping. const(this) { int foo(); int bar(); } but, just look what /else/ you could do with it! const(x) /* let x be const within these braces */ { /* x is const here */ } or... int x = 42; const(x): /* x is const from here on */ x = 100; /* error */ Why, it's almost like having final back! (Only, with crystal clear syntax and without the confusion). Other advantages include const(outer) allows you to check const correctness via outer instead of via this. That is, "I promise not to modify any member variables of an outer class". And so on. Going back to Walter's point that C++ allows const as a storage class just fine, I want to really stress that that claim is a red herring. When you declare a member function as const in C++, you are /not/ using "const the storage class". In fact, in C++, "const the storage class" is really the same thing as D's invariant type constructor - it is an assertion that the variable will never be changed, ever. It certainly doesn't mean "don't modify 'this'". That's why I think it's important to separate in our minds the distinction between "storage class" and "attribute". There are places in D where the existing const syntax is just fine - e.g. Walter's example const x = 5; However, just because we want that to be a legal statement, it does not follow that we need to give the keyword const (without brackets) all the syntactic abilities of an attribute. On the other hand, const(identifier) makes absolutely /perfect/ sense as an attribute. It's beautiful, and would give us expressive power that even C++ doesn't have, while at the same time allowing everything that Walter wants to keep with only minor syntactic changes (e.g. "const(this)" instead of "const" for member functions, const-statements in the grammar instead of "const" as an attribute). This is a testing time for const. We're already doing better than C++ in many respects, but the final deal still isn't nailed down yet, so while there's still time, let's consider this one. There are people who haven't upgraded to D2 yet - they obviously won't mind the change; there are those of us who like to "live on the edge" - well, we won't mind change either, because we understand that's the price for living on the edge. So the proposal is: (1) disallow "const" as an attribute (2) introduce "const statements" so that "const x = 5" still compiles. (3) allow "const(identifer)" to be an attribute, which makes identifier const within the scope of the attribute and likewise for invariantOn 11/27/07, David Gileadi <foo bar.com> wrote:Me too.While maybe a bit of typing, I really like the const(this) form--its intent is very clear IMHO. And const(this) { int foo(); int bar(); } isn't too bad either.For what it's worth, I completely agree with this.
Nov 28 2007
Janice Caron wrote:A thought occurs to me. (And it's a good one).I think so, too. It'd help whenever I have a hairy method with lots of locals that I was having trouble keeping track of. There's a small problem of scope, but that's manageable: // var1 should be const starting here... const(var1) { ... // var2 should be const starting here... const(var2) { ... // make var1 non-const now } } const(var2) { ... // mave var2 non-const now } Of course, maintaining a large method with several of these const windows might be a bit troublesome. But it replaces some hard-to-find bugs with some easy-to-find ones.
Nov 28 2007
Christopher Wright wrote:Janice Caron wrote:I suspect you'd also be able to do something along the lines of: { const(var1): const(var2): ... }// end var1,var2 constness Anyway, the same kind of scoping mess exists now with 'with'. I've long wanted a 'with(var1):' form of it. --bbA thought occurs to me. (And it's a good one).I think so, too. It'd help whenever I have a hairy method with lots of locals that I was having trouble keeping track of. There's a small problem of scope, but that's manageable: // var1 should be const starting here... const(var1) { ... // var2 should be const starting here... const(var2) { ... // make var1 non-const now } } const(var2) { ... // mave var2 non-const now } Of course, maintaining a large method with several of these const windows might be a bit troublesome. But it replaces some hard-to-find bugs with some easy-to-find ones.
Nov 28 2007
Janice Caron wrote:On Nov 28, 2007 11:45 AM, Don Clugston <dac nospam.com.au> wrote: A thought occurs to me. (And it's a good one). Since we're considering making const(this) an attribute, why not extend it to const(identifier), for any identifier. That is, const(identifier) would syntactically be considered an attribute, and could go anywhere version(identifier) could go. It's meaning would be: within the specified scope, the named identifier shall be consisdered const (and likewise for invariant). Allowing "this" to be merely a special case of identifier, does indeed allow us to declare const member functions: const(this) void f(); as well as the abovementioned grouping. const(this) { int foo(); int bar(); } but, just look what /else/ you could do with it! const(x) /* let x be const within these braces */ { /* x is const here */ }I guess in C++ you'd do that by making a const reference to x: { const int& const_x = x; /* use const_x insted of x here } But I can't say that I've wanted to do that very often in C++. Of course the renaming and introduction of indirection that the compiler may not optimize away is a bit more cumbersome than what you propose. Still, even if it wouldn't be particularly useful, the generality is elegant. :-)or... int x = 42; const(x): /* x is const from here on */ x = 100; /* error */ Why, it's almost like having final back! (Only, with crystal clear syntax and without the confusion). Other advantages includeI don't see how it replaces final (aka head-const). It just allows you to move the "const" around and scope it. int[] x = [42]; const(x): /* x is const from here on */ x[0] = 100; /* error - x is const, not head-const */const(outer) allows you to check const correctness via outer instead of via this. That is, "I promise not to modify any member variables of an outer class". And so on.Now that does sound useful. --bb
Nov 28 2007
(2) introduce "const statements" so that "const x = 5" still compiles.I guess that should really be "const declarations", not "const statements". But you get the drift.
Nov 28 2007
Janice Caron wrote:On 11/27/07, David Gileadi <foo bar.com> wrote:I like it too. It's extremely clear and never ambiguous.While maybe a bit of typing, I really like the const(this) form--its intent is very clear IMHO. And const(this) { int foo(); int bar(); } isn't too bad either.For what it's worth, I completely agree with this. I think it's a fine syntax, and makes the intent very clear. It can go at the front of a function without any confusion, it's obvious what it means, and the extention to invariant(this) is equally as obvious. In the extreme unlikelihood that I have a vote, this one gets mine.
Nov 29 2007