digitalmars.D - Const sucks
- Walter Bright (48/48) Sep 10 2007 Const, final, invariant, head const, tail const, it's grown into a
- Regan Heath (18/26) Sep 10 2007 How is this going to work for a more complex struct?
- Janice Caron (6/6) Sep 10 2007 Wow! Well, I'm happy! :-)
- Jb (6/8) Sep 10 2007 Am I the only one who though it odd that the current documentation spend...
- Janice Caron (2/4) Sep 10 2007 As of the start of this thread, the current documentation is out the win...
- Walter Bright (3/5) Sep 10 2007 Half of D programmers come from C++, and the easiest way to learn
- Walter Bright (2/6) Sep 10 2007 Yes.
- Sean Kelly (12/40) Sep 10 2007 So the presence of parenthesis would be simply to limit the extent of
- Walter Bright (10/40) Sep 10 2007 Yes. Think of the () as presenting an 'argument' to be const-ified.
- Alexander Panek (2/4) Sep 10 2007 What exactly is the is the difference between head and tail const?
- Janice Caron (13/14) Sep 10 2007 Suppose you have a pointer to pointer to pointer to pointer to pointer t...
- Bobba Fett (5/24) Sep 10 2007 This highlights another source of confusion for me. I assumed tail cons...
- Janice Caron (15/22) Sep 10 2007 While that does make sense, I guess what we really want to know is why
- Sean Kelly (7/31) Sep 10 2007 Okay, so basically if I want a mutable struct that may reference
- Derek Parnell (17/53) Sep 10 2007 Ok, nice to see this documented.
- Janice Caron (2/6) Sep 10 2007 I believe I can answer that. They are all syntax errors.
- Gregor Richards (9/13) Sep 10 2007 const: I promise not to change this, but acknowledge that somebody else
- Derek Parnell (9/27) Sep 10 2007 Thank you. I do rememeber now ... silly how I couldn't get that from the
- renoX (10/15) Sep 11 2007 So am I, each time I see 'invariant' I try to think 'value', which is
- renoX (5/25) Sep 11 2007 Oops, I didn't see the change that now you can take the address of an
- Walter Bright (7/10) Sep 10 2007 const is useless for optimization, invariant is very useful for
- Janice Caron (5/5) Sep 10 2007 You might want to allow
- Walter Bright (4/12) Sep 10 2007 invariant(const(...)) will have to be accepted, and it will be treated
- Bill Baxter (24/32) Sep 10 2007 So then it would be ok to completely overrwrite an S, but not to set
- Walter Bright (12/27) Sep 10 2007 'const' means a I can't change it (but someone else can, such as someone
- Derek Parnell (28/63) Sep 10 2007 Thank you. Because the terms in English are synonyms, its a bit hard,
- Janice Caron (15/26) Sep 11 2007 I don't think you're misunderstanding. I think that's what Walter is say...
- Derek Parnell (18/38) Sep 12 2007 But why templates?!?!?
- Regan Heath (20/57) Sep 12 2007 No, I don't think so.
- Regan Heath (7/73) Sep 12 2007 To clarify (I hope).
- Bruno Medeiros (7/13) Sep 10 2007 'invariant' = constant
- Janice Caron (8/10) Sep 11 2007 It's simple, but - I would argue - the wrong choice. A better choice (in...
- Janice Caron (11/17) Sep 11 2007 By which I mean, if it's at all feasable to consider ditching the keywor...
- Bill Baxter (7/32) Sep 11 2007 It has been suggested before several times. The problem is there's
- Daniel Keep (9/43) Sep 11 2007 The problem is that, broadly speaking, all these words mean the same
- Derek Parnell (11/54) Sep 11 2007 Therefore let's invent some new keywords, ones that are unlikely to clas...
- Janice Caron (11/13) Sep 11 2007 Coined words! Wow - now there's a thought!
- Oskar Linde (44/60) Sep 11 2007 They are. The meaning of words is very domain dependent is often based
- Bruno Medeiros (14/86) Sep 11 2007 I agree. (Damn, I always agree with you Oskar :P )
- Bruno Medeiros (6/13) Sep 11 2007 It was quite naive to think that no one had suggested keyword changes
- Janice Caron (21/21) Sep 11 2007 Content-Disposition: inline
- Nicolai Waniek (38/55) Sep 11 2007 This would translate to something else coming from Delphi, the "property...
- Janice Caron (10/12) Sep 11 2007 I think you may have missed the point there. We can already do that with...
- Bruno Medeiros (11/24) Sep 11 2007 I must withdraw somewhat my comment that "it's simple", since
- Janice Caron (5/7) Sep 10 2007 Two ways of writing the same thing. I don't understand the need for
- Regan Heath (4/13) Sep 10 2007 I thought the same thing. I suspect the brackets will remain optional,
- Janice Caron (5/7) Sep 10 2007 Two ways of writing the same thing. I don't understand the need for
- Nathan Reed (6/15) Sep 10 2007 I'd rather have the bracketless version to save typing in the case when
- Walter Bright (12/19) Sep 10 2007 The bracketless version is for two reasons:
- Carlos Santander (6/76) Sep 10 2007 Am I the only one who doesn't like this syntax? I guess it kinda makes s...
- Nathan Reed (9/19) Sep 10 2007 Seems to me like this unnecessarily departs from the macro syntax
- Bill Baxter (8/28) Sep 10 2007 It's not far off from things used in some functional programming
- Jari-Matti =?ISO-8859-1?Q?M=E4kel=E4?= (5/33) Sep 10 2007 And let's take another step forward (might scare off some old C farts,
- Downs (19/52) Sep 10 2007 -----BEGIN PGP SIGNED MESSAGE-----
- Bruce Adams (7/24) Sep 10 2007 I'm not clear why this is even needed.
- Walter Bright (3/13) Sep 10 2007 windows.h in all its terrifying glory has 10,000 macro declarations. If
- Sean Kelly (6/21) Sep 10 2007 That sounds about right. When we converted const values to enum values
- Bruce Adams (10/34) Sep 10 2007 I seek enlightenmnet for at least two problems with that explanation.
- Sean Kelly (13/46) Sep 11 2007 htod works for simple cased. More complex cases require GregorR's BCD
- Russell Lewis (14/27) Sep 10 2007 I'd like to suggest that we use some keyword other than "static." Yeah,...
- Janice Caron (3/6) Sep 10 2007 We use private for that purpose in D, so static is free to be retooled
- Bruno Medeiros (8/20) Sep 10 2007 No one cares (or at least, should care) what that means in C. That's
- Bill Baxter (14/36) Sep 10 2007 Does c) include being able to pass literal arguments to functions
- Russell Lewis (7/14) Sep 10 2007 Is there a way to express (for a pointer passed as a function parameter)...
- Gregor Richards (5/21) Sep 10 2007 It would probably be easy enough to add such a type modifier, but
- Russell Lewis (10/31) Sep 10 2007 I agree that there's no magic-bullet for concurrency, but there *are*
- Walter Bright (6/20) Sep 10 2007 That's sort of what the often proposed 'unique' type qualifier does. The...
- Bruce Adams (9/30) Sep 10 2007 I see a least two ways of interpreting it at run-time.
- Jason House (13/34) Sep 10 2007 Except for the most pathological cases, I believe there are some
- Jason House (2/3) Sep 10 2007 The pathological case that I'm aware of is recursion.
- Bruce Adams (4/8) Sep 11 2007 [OT]
- Bruce Adams (3/19) Sep 10 2007 That's an interesting concept. From the functions point of view it would...
- Bruno Medeiros (11/31) Sep 10 2007 Then, there will no longer be a final "storage class" for var declaratio...
- Walter Bright (2/6) Sep 10 2007 What, exactly, is the use case that needs a solution?
- Bruno Medeiros (13/20) Sep 10 2007 Before hand, let me just say that by broken, I didn't mean subvertable,
- Walter Bright (3/17) Sep 10 2007 You can't sort an (array of)(const T). You can sort an (array
- Robert Fraser (2/20) Sep 10 2007 That worries me (not that case in particular, but general constness + cl...
- Walter Bright (3/8) Sep 10 2007 It worries me in the abstract, but I've not been able to find a real
- Robert Fraser (16/25) Sep 10 2007 Here's an easy one: returning constant class references from an opApply....
- Nathan Reed (19/37) Sep 10 2007 I may be misunderstanding this. When you declare an array const(C)[]
- Bruno Medeiros (12/19) Sep 10 2007 Here's another use case, which is significantly different than the other...
- Walter Bright (5/18) Sep 10 2007 I'd redesign String so it holds invariant data, then just have:
- Bruno Medeiros (13/34) Sep 11 2007 Err... you do realize what this implies? This example holds not just for...
- BCS (4/4) Sep 10 2007 There is no way to find an optimal const solution without trying every p...
- Miles (28/31) Sep 10 2007 I was going to say that, that D's const sucks, many months ago, but
- Downs (15/21) Sep 10 2007 -----BEGIN PGP SIGNED MESSAGE-----
- Miles (7/9) Sep 10 2007 Yes, it was... :-P read: This is where you should first aim your laser.
- eao197 (5/36) Sep 11 2007 I'm totaly agree with all you have said.
- Myron Alexander (19/26) Sep 10 2007 Walter, how are references handled and can you create a tail const of a
- Bruce Adams (51/121) Sep 11 2007 Time for a rethink. I think I may have (part of) a solution.
- Daniel Keep (63/104) Sep 11 2007 Not 100% sure what you mean by "no more". But then, "final" was always
- Regan Heath (64/92) Sep 11 2007 I came to the same conclusion, the basic problem is the inability to put...
- Regan Heath (27/31) Sep 11 2007 Talking to myself, a sure sign of mental instability ;)
- eao197 (6/8) Sep 11 2007 What's wrong with such pointers and why they are disabled by language?
- Steven Schveighoffer (44/64) Sep 11 2007 Overall, I like this solution MUCH better than before. I have some poin...
- Nathan Reed (16/20) Sep 11 2007 For numeric constants which are known at compile time, there's not
- Janice Caron (12/17) Sep 11 2007 Then just decree that it be illegal to take the address of a const
- 0ffh (7/10) Sep 11 2007 Hmmmm... if I got that right, macros will definitely *not* be "pieces
- Janice Caron (14/18) Sep 11 2007 Macros have their place. I'm not knocking them. But they're not the
- Regan Heath (5/33) Sep 11 2007 You're jumping to conclusions here. I doubt _very_ much that Walter
- 0ffh (4/12) Sep 11 2007 It is! You'll be able to do "typeof(x)" and probably get "int"... :-)
- Nathan Reed (10/22) Sep 11 2007 That places totally unnecessary restrictions on the programmer...there's...
- Regan Heath (3/26) Sep 11 2007 In that way it's a bit like 'auto'
- Janice Caron (20/29) Sep 11 2007 Remember, this is a special circumstance - /as a class member variable/
- Nathan Reed (26/50) Sep 11 2007 Fine for things that are known at compile time. But it's also possible
- Janice Caron (25/44) Sep 11 2007 That's not a class member variable. That's a local variable. It's a
- Regan Heath (12/24) Sep 11 2007 No problem:
- Janice Caron (4/9) Sep 11 2007 Maybe it's just a gut feeling thing.
- Janice Caron (7/9) Sep 11 2007 Otherwise I'll end up doing
- Janice Caron (9/15) Sep 11 2007 Of course, I actually meant:
- Myron Alexander (33/33) Sep 11 2007 This is a mess!
- Janice Caron (22/28) Sep 11 2007 I'd hadn't really thought about this before. But now I have.
- Nathan Reed (4/12) Sep 11 2007 Agree.
- Paul Anderson (5/10) Sep 11 2007 This seems to have generated a lot of discussion...
- Bruce Adams (4/57) Sep 11 2007 I strongly disapprove of designing language features based around a part...
- Bruce Adams (2/16) Sep 11 2007 Already agreed on another thread but worth every extra vote.
- Charles (2/20) Sep 11 2007
- Oskar Linde (78/81) Sep 11 2007 I have not really been following the discussions thus far, but would
- Bruno Medeiros (6/8) Sep 12 2007 Are you sure? How would that work in general terms, for say, a class?
- Funog (2/13) Sep 12 2007 If head const is not necessary, why not having const and invariant meani...
- charles (2/72) Sep 12 2007
Const, final, invariant, head const, tail const, it's grown into a monster. It tries to cover all the bases, but in doing so is simply not understandable. Andrei and Bartosz have spent some time together going back to square one with what are we trying to achieve with const, and came up with another proposal. What we are trying to achieve: a) utility for functional programming b) better modularity by self-documenting interfaces better c) be able to treat reference types as if they were value types (i.e. strings should behave to the user like value types, even though they are references) The insights they came up with were: 1) final (i.e. 'head const') is not necessary for a, b or c. final is a local thing, and not strictly necessary. 2) tail const can be handled in other ways, read on So, what we are left with is: o no more final o const and invariant now mean "fully const" and "fully invariant", where fully means "head and tail combined": const int x = 0; // x is constant const int* p = &x; // neither p nor *p can be changed const(int*) p = &x; // neither p nor *p can be changed const(int)* p = &x; // p can change, *p cannot be changed o const and invariant are transitive. There is no way to specify a (pointer to)(const pointer to)(mutable int). o tail invariant for an array or pointer type can be done using the existing syntax: invariant(char)[] s; // string, i.e. an array of invariant chars const(T)* p; // pointer to tail const T o tail const of a struct would have to be done by making the struct a template: struct S(T) { T member; } S!(int) // tail mutable S!(const(int)) // tail const o one can construct a template to generically produce tail const or tail invariant versions of a type. o it will be illegal to attempt to change the key value of a foreach loop, but the compiler will not be able to diagnose all attempts to do so o static const/invariant means the initializer is evaluated at compile time. non-static const/invariant means it is evaluated at run time. o no initializer means it is assigned in the corresponding constructor. o const/invariant declarations will always allocate memory (so their addresses can be taken) o So, we still need a method to declare a constant that will not consume memory. We'll co-opt the future macro syntax for that: macro x = 3; macro s = "hello";
Sep 10 2007
Walter Bright wrote:o tail const of a struct would have to be done by making the struct a template: struct S(T) { T member; } S!(int) // tail mutable S!(const(int)) // tail constHow is this going to work for a more complex struct? struct Bar { int a; } class Baz { int a; } struct Foo { int a; float b; char[] c; Bar d; Baz e; }o one can construct a template to generically produce tail const or tail invariant versions of a type.Including classes? I saw no mention of how tail-const will be applied to classes, will they be handled in the same way as structs? In general is this correct for a class reference: class Baz { int a; } const Baz b; //neither b nor b.a can be changed Regan
Sep 10 2007
Wow! Well, I'm happy! :-) I think I'll wait for the documentation before I comment further, except to mention again this suggestions which I've made elsewhere... No casting away const except by special syntax. const(int)*p; auto q = (int *) p; // Error - p is const
Sep 10 2007
"Janice Caron" <caron800 googlemail.com> wrote in message news:mailman.136.1189453181.16939.digitalmars-d puremagic.com...Wow! Well, I'm happy! :-) I think I'll wait for the documentation before I comment further,Am I the only one who though it odd that the current documentation spends twice as much time talking about C++ than it does about D? It's almost feels like the coverage of final and invariant were last minute additions just before handing it in for marking.
Sep 10 2007
On 9/10/07, Jb <jb nowhere.com> wrote:Am I the only one who though it odd that the current documentation spends twice as much time talking about C++ than it does about D?As of the start of this thread, the current documentation is out the window. :-)
Sep 10 2007
Jb wrote:Am I the only one who though it odd that the current documentation spends twice as much time talking about C++ than it does about D?Half of D programmers come from C++, and the easiest way to learn something new is to relate it to something already known.
Sep 10 2007
"Walter Bright" <newshound1 digitalmars.com> wrote in message news:fc4mu5$2j7u$3 digitalmars.com...Jb wrote:Yeah thats fair enough up to a point, but imo the D section was sorely lacking in examples and detailed explanations. Hence all the "What does const xyz mean?" questions in the newgroup.Am I the only one who though it odd that the current documentation spends twice as much time talking about C++ than it does about D?Half of D programmers come from C++, and the easiest way to learn something new is to relate it to something already known.
Sep 10 2007
"Jb" <jb nowhere.com> wrote in message news:fc4stj$2snr$1 digitalmars.com..."Walter Bright" <newshound1 digitalmars.com> wrote in message news:fc4mu5$2j7u$3 digitalmars.com...Sorry to clarify, i meant the the D section was too light, not the C++ section too heavy.Jb wrote:Yeah thats fair enough up to a point, but imo the D section was sorely lacking in examples and detailed explanations. Hence all the "What does const xyz mean?" questions in the newgroup.Am I the only one who though it odd that the current documentation spends twice as much time talking about C++ than it does about D?Half of D programmers come from C++, and the easiest way to learn something new is to relate it to something already known.
Sep 10 2007
Regan Heath wrote:In general is this correct for a class reference: class Baz { int a; } const Baz b; //neither b nor b.a can be changedYes.
Sep 10 2007
Walter Bright wrote:So, what we are left with is: o no more finalBy this you meant that "final" in 2.0 would work exactly as in 1.0, correct?o const and invariant now mean "fully const" and "fully invariant", where fully means "head and tail combined": const int x = 0; // x is constant const int* p = &x; // neither p nor *p can be changed const(int*) p = &x; // neither p nor *p can be changed const(int)* p = &x; // p can change, *p cannot be changedSo the presence of parenthesis would be simply to limit the extent of the type to which "const" applies? As an aside, I'm still not terribly fond of 'invariant', but that's a cosmetic issue which could easily be resolved later.o const and invariant are transitive. There is no way to specify a (pointer to)(const pointer to)(mutable int).Sounds great to me.o tail invariant for an array or pointer type can be done using the existing syntax: invariant(char)[] s; // string, i.e. an array of invariant chars const(T)* p; // pointer to tail const T o tail const of a struct would have to be done by making the struct a template: struct S(T) { T member; } S!(int) // tail mutable S!(const(int)) // tail const o one can construct a template to generically produce tail const or tail invariant versions of a type.Could you please explain this further? Why would templates be needed in the above two points? For the rest, this design sounds a lot more comprehensible than the old one, and still seems to address all the situations where I would use const. Sean
Sep 10 2007
Sean Kelly wrote:Walter Bright wrote:Yes. There'll still be final classes and final virtual functions.So, what we are left with is: o no more finalBy this you meant that "final" in 2.0 would work exactly as in 1.0, correct?Yes. Think of the () as presenting an 'argument' to be const-ified.o const and invariant now mean "fully const" and "fully invariant", where fully means "head and tail combined": const int x = 0; // x is constant const int* p = &x; // neither p nor *p can be changed const(int*) p = &x; // neither p nor *p can be changed const(int)* p = &x; // p can change, *p cannot be changedSo the presence of parenthesis would be simply to limit the extent of the type to which "const" applies?Think of a struct which was your own implementation of arrays: struct Array(T) { T[] a; } To create a tail const array, instead of const(T)[], we'd do Array!(const(T)).o tail const of a struct would have to be done by making the struct a template: struct S(T) { T member; } S!(int) // tail mutable S!(const(int)) // tail const o one can construct a template to generically produce tail const or tail invariant versions of a type.Could you please explain this further? Why would templates be needed in the above two points?
Sep 10 2007
Walter Bright wrote:To create a tail const array, instead of const(T)[], we'd do Array!(const(T)).What exactly is the is the difference between head and tail const?
Sep 10 2007
On 9/10/07, Alexander Panek <a.panek brainsware.org> wrote:What exactly is the is the difference between head and tail const?Suppose you have a pointer to pointer to pointer to pointer to pointer to int. (The length of this chain is irrelevant. I just threw lots in for the hell of it). Head const would be const pointer to pointer to pointer to pointer to pointer to int. Tail const would be pointer to const pointer to const pointer to const pointer to const pointer to const int. Total const would be const pointer to const pointer to const pointer to const pointer to const pointer to const int. i.e. head const and tail const both at the same time.
Sep 10 2007
Janice Caron Wrote:On 9/10/07, Alexander Panek <a.panek brainsware.org> wrote:This highlights another source of confusion for me. I assumed tail const would be pointer to pointer to pointer .... to const int. What you have described I would call "rest const" using naive intuition.What exactly is the is the difference between head and tail const?Suppose you have a pointer to pointer to pointer to pointer to pointer to int. (The length of this chain is irrelevant. I just threw lots in for the hell of it). Head const would be const pointer to pointer to pointer to pointer to pointer to int. Tail const would be pointer to const pointer to const pointer to const pointer to const pointer to const int.Total const would be const pointer to const pointer to const pointer to const pointer to const pointer to const int. i.e. head const and tail const both at the same time.
Sep 10 2007
On 9/10/07, Walter Bright <newshound1 digitalmars.com> wrote:Think of a struct which was your own implementation of arrays: struct Array(T) { T[] a; } To create a tail const array, instead of const(T)[], we'd do Array!(const(T)).While that does make sense, I guess what we really want to know is why we won't be able to do this: struct MyArray { int[] p; } and then make a tail const version with some magic keyword like tailconst(MyArray) That is, tailconst(T) could be some built-in keyword which created a new type which was just like T except that all its pointers would be const. Are you saying this is such a rare thing to want to do that it's not worth supporting generically? I can't say I've ever needed it up to now.
Sep 10 2007
Walter Bright wrote:Sean Kelly wrote:Okay, so basically if I want a mutable struct that may reference constant data I'll have to pass the const attribute through via a template rather than preceding the struct decl with a "tail const" keyword. Is that right? Seems fair enough. C++ requires the same approach, as far as I know. SeanThink of a struct which was your own implementation of arrays: struct Array(T) { T[] a; } To create a tail const array, instead of const(T)[], we'd do Array!(const(T)).o tail const of a struct would have to be done by making the struct a template: struct S(T) { T member; } S!(int) // tail mutable S!(const(int)) // tail const o one can construct a template to generically produce tail const or tail invariant versions of a type.Could you please explain this further? Why would templates be needed in the above two points?
Sep 10 2007
On Mon, 10 Sep 2007 12:15:09 -0700, Walter Bright wrote:Const, final, invariant, head const, tail const, it's grown into a monster. It tries to cover all the bases, but in doing so is simply not understandable.Agreed!Andrei and Bartosz have spent some time together going back to square one with what are we trying to achieve with const, and came up with another proposal. What we are trying to achieve: a) utility for functional programming b) better modularity by self-documenting interfaces better c) be able to treat reference types as if they were value types (i.e. strings should behave to the user like value types, even though they are references)Ok, nice to see this documented.The insights they came up with were: 1) final (i.e. 'head const') is not necessary for a, b or c. final is a local thing, and not strictly necessary. 2) tail const can be handled in other ways, read on So, what we are left with is: o no more finalNot a problem for me as I never used it.o const and invariant now mean "fully const" and "fully invariant", where fully means "head and tail combined":Remind me again what the difference between 'const' and 'invariant' is.const int x = 0; // x is constant const int* p = &x; // neither p nor *p can be changed const(int*) p = &x; // neither p nor *p can be changed const(int)* p = &x; // p can change, *p cannot be changedWhat do these below mean ... const int (* p) const int *(p) const int (*) po tail const of a struct would have to be done by making the struct a template: struct S(T) { T member; } S!(int) // tail mutable S!(const(int)) // tail constBut most structs contain multiple members, and usually of different types. -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
Sep 10 2007
What do these below mean ... const int (* p) const int *(p) const int (*) pI believe I can answer that. They are all syntax errors. The stuff inside the brackets needs to be a valid type expression.
Sep 10 2007
Derek Parnell wrote:const: I promise not to change this, but acknowledge that somebody else might. invariant: Neither I nor anyone else will change this. const has a more limited use for optimization than invariant, since the value could be changed by other threads/programs-with-shm/whatever from under you. - Gregor Richards PS: Or at least, this is my understanding :)o const and invariant now mean "fully const" and "fully invariant", where fully means "head and tail combined":Remind me again what the difference between 'const' and 'invariant' is.
Sep 10 2007
On Mon, 10 Sep 2007 12:55:29 -0700, Gregor Richards wrote:Derek Parnell wrote:Thank you. I do rememeber now ... silly how I couldn't get that from the keywords. 'const' is sort of a locally write protected. 'invariant' is globally write protected. -- Derek Parnell Melbourne, Australia skype: derek.j.parnellconst: I promise not to change this, but acknowledge that somebody else might. invariant: Neither I nor anyone else will change this. const has a more limited use for optimization than invariant, since the value could be changed by other threads/programs-with-shm/whatever from under you. - Gregor Richards PS: Or at least, this is my understanding :)o const and invariant now mean "fully const" and "fully invariant", where fully means "head and tail combined":Remind me again what the difference between 'const' and 'invariant' is.
Sep 10 2007
Derek Parnell a écrit :Thank you. I do remember now ... silly how I couldn't get that from the keywords. 'const' is sort of a locally write protected. 'invariant' is globally write protected.So am I, each time I see 'invariant' I try to think 'value', which is much more easy to associate with the correct properties: values are immutable and you can't take the address of a value either, exactly like 'invariant'. For const, I've not found an easy to memorize keyword, but as D's const are like C++ const (AFAIK), it's not an issue for me. Of course with a Limbo syntax for variable declaration instead of the weird C-like, the parenthesis would be less(not?) useful.. renoX
Sep 11 2007
renoX a écrit :Derek Parnell a écrit :Oops, I didn't see the change that now you can take the address of an invariant. So now invariant != value, argh. renoXThank you. I do remember now ... silly how I couldn't get that from the keywords. 'const' is sort of a locally write protected. 'invariant' is globally write protected.So am I, each time I see 'invariant' I try to think 'value', which is much more easy to associate with the correct properties: values are immutable and you can't take the address of a value either, exactly like 'invariant'.For const, I've not found an easy to memorize keyword, but as D's const are like C++ const (AFAIK), it's not an issue for me. Of course with a Limbo syntax for variable declaration instead of the weird C-like, the parenthesis would be less(not?) useful.. renoX
Sep 11 2007
Gregor Richards wrote:const has a more limited use for optimization than invariant, since the value could be changed by other threads/programs-with-shm/whatever from under you.const is useless for optimization, invariant is very useful for optimization. But it turns out that if you have invariant, soon you'll discover that you need const. Otherwise you'll find that every function will have to be implemented two or more times (*). (*) Because invariants cannot be implicitly converted to mutable, and vice versa.
Sep 10 2007
You might want to allow const(invariant(int)*)* p; p is a mutable pointer to a const pointer to an invariant int. Since invariant is "stronger" than const, you want to be able to do const(invariant(...)), but not invariant(const(...))
Sep 10 2007
Janice Caron wrote:You might want to allow const(invariant(int)*)* p; p is a mutable pointer to a const pointer to an invariant int. Since invariant is "stronger" than const, you want to be able to do const(invariant(...)), but not invariant(const(...))invariant(const(...)) will have to be accepted, and it will be treated as invariant(invariant(...)). This is just for building a type - it doesn't re-type any data.
Sep 10 2007
Derek Parnell wrote:On Mon, 10 Sep 2007 12:15:09 -0700, Walter Bright wrote:So then it would be ok to completely overrwrite an S, but not to set it's only member directly? alias S!(const(int)) T; T a; T b; a = b; // ok?? a.member = b.member; // not ok?? It seems a little odd since they do exactly the same thing. Hopefully copying a struct will be treated the same as elementwise copying of the members (so both should be illegal above).o tail const of a struct would have to be done by making the struct a template: struct S(T) { T member; } S!(int) // tail mutable S!(const(int)) // tail constBut most structs contain multiple members, and usually of different types.Probably someone clever will create a type-constructor template that generates constified version of a given struct type using __traits or something. Then you'll just do alias MakeConst!(MyStruct) MyConstStruct; If not, we'll just keep pestering Walter until it is possible to write such a template. :=) Probably more realistic is a case where you want to switch between struct T { int* x; int y; } and struct T { const(int)*; int y; } So the const doesn't start on the member level, but stuff-pointed-to-by-members level --bb
Sep 10 2007
Derek Parnell wrote:Remind me again what the difference between 'const' and 'invariant' is.'const' means a I can't change it (but someone else can, such as someone in a different thread). 'invariant' means nuttin' can change it, not no-how, not no-way.What do these below mean ... const int (* p)syntax errorconst int *(p)syntax errorconst int (*) psyntax error Imagine if const were a template called Const, and we used that template to form a new type that was const of the old type. We'd invoke it like: Const!(T) t; Now, just s/Const!/const/, and the syntax should make sense.That's up to the struct designer.o tail const of a struct would have to be done by making the struct a template: struct S(T) { T member; } S!(int) // tail mutable S!(const(int)) // tail constBut most structs contain multiple members, and usually of different types.
Sep 10 2007
On Mon, 10 Sep 2007 15:22:23 -0700, Walter Bright wrote:Derek Parnell wrote:Thank you. Because the terms in English are synonyms, its a bit hard, without constant usage, to remember this stuff. Of course, once it is permanently in D and I'm using it all the time, no doubt it'll stick ... pity about the newbies though.Remind me again what the difference between 'const' and 'invariant' is.'const' means a I can't change it (but someone else can, such as someone in a different thread). 'invariant' means nuttin' can change it, not no-how, not no-way.Thanks. I thought as much.What do these below mean ... const int (* p)syntax errorconst int *(p)syntax errorconst int (*) psyntax error Imagine if const were a template called Const, and we used that template to form a new type that was const of the old type. We'd invoke it like: Const!(T) t; Now, just s/Const!/const/, and the syntax should make sense.What does that answer mean?!?!?! Ok, let's back up a second. You say "struct S(T) { T member; } S!(int) // tail mutable S!(const(int)) >>> // tail const" to which I assumed you meant that you can ONLY have tail const structs if every member of the struct is of a type mentioned in the template argument. In other words, if I have a struct with three members, each of a different type, I need to code ... struct S3(T, U, V) { T member1; U member2; V member3; } S3!(const(int), const(float), const(bool)); and so on for 4, 5, 6, .... 23 member structs. I'm sure I'm misunderstanding you, because this is really silly. -- Derek (skype: derek.j.parnell) Melbourne, Australia 11/09/2007 10:52:30 AMThat's up to the struct designer.o tail const of a struct would have to be done by making the struct a template: struct S(T) { T member; } S!(int) // tail mutable S!(const(int)) // tail constBut most structs contain multiple members, and usually of different types.
Sep 10 2007
Content-Disposition: inline On 9/11/07, Derek Parnell <derek nomail.afraid.org> wrote:In other words, if I have a struct with three members, each of a different type, I need to code ... struct S3(T, U, V) { T member1; U member2; V member3; } S3!(const(int), const(float), const(bool)); and so on for 4, 5, 6, .... 23 member structs. I'm sure I'm misunderstanding you, because this is really silly.I don't think you're misunderstanding. I think that's what Walter is saying. But here's another idea. If it were allowable that (1) an alias template parameter could accept a type constructor, and (2) "auto" were accepted as a do-nothing type constructor then you would be able to do this: struct S(alias X) { X(int)* pi; X(float)* pf; X(double)* pd; }; S(const) k; // k's members are tail-const S(auto) m; // m's members are mutable
Sep 11 2007
On Tue, 11 Sep 2007 10:10:33 +0100, Janice Caron wrote:On 9/11/07, Derek Parnell <derek nomail.afraid.org> wrote:But why templates?!?!? How is that different from ... struct S3 { const(int) member1; const(float) member2; const(bool) member3; } No template involved. I'm reading Walter as saying that if any struct definition involves any of its members being const/invariant, then one must define that struct in terms of templates. Is this what Walter is really saying? -- Derek (skype: derek.j.parnell) Melbourne, Australia 12/09/2007 6:31:57 PMIn other words, if I have a struct with three members, each of a different type, I need to code ... struct S3(T, U, V) { T member1; U member2; V member3; } S3!(const(int), const(float), const(bool)); and so on for 4, 5, 6, .... 23 member structs. I'm sure I'm misunderstanding you, because this is really silly.I don't think you're misunderstanding. I think that's what Walter is saying.
Sep 12 2007
Derek Parnell wrote:On Tue, 11 Sep 2007 10:10:33 +0100, Janice Caron wrote:No, I don't think so. I believe he is saying that if you have a struct, eg. struct S1 { int a; float b; } and you want to use it, as is, in one place in your code but also use a const version of this same struct somewhere else then you need to use a template to create a modified struct definition to use. If you simply want to convert a struct from non-const aware to const-aware you can just add const to the definition and recompile. If you simply want to have a const copy of the struct somewhere you can just use const(S1), eg. class Bob { const(S1) data; } ReganOn 9/11/07, Derek Parnell <derek nomail.afraid.org> wrote:But why templates?!?!? How is that different from ... struct S3 { const(int) member1; const(float) member2; const(bool) member3; } No template involved. I'm reading Walter as saying that if any struct definition involves any of its members being const/invariant, then one must define that struct in terms of templates. Is this what Walter is really saying?In other words, if I have a struct with three members, each of a different type, I need to code ... struct S3(T, U, V) { T member1; U member2; V member3; } S3!(const(int), const(float), const(bool)); and so on for 4, 5, 6, .... 23 member structs. I'm sure I'm misunderstanding you, because this is really silly.I don't think you're misunderstanding. I think that's what Walter is saying.
Sep 12 2007
Regan Heath wrote:Derek Parnell wrote:To clarify (I hope). A template is only required if you want to _tail_ const certain members (or even all) of an existing struct in some instances but not all instances. Complete const can be achived with const(S1) and tail const on all instances can be achieved by editing the struct difinition and recompiling. ReganOn Tue, 11 Sep 2007 10:10:33 +0100, Janice Caron wrote:No, I don't think so. I believe he is saying that if you have a struct, eg. struct S1 { int a; float b; } and you want to use it, as is, in one place in your code but also use a const version of this same struct somewhere else then you need to use a template to create a modified struct definition to use. If you simply want to convert a struct from non-const aware to const-aware you can just add const to the definition and recompile. If you simply want to have a const copy of the struct somewhere you can just use const(S1), eg. class Bob { const(S1) data; }On 9/11/07, Derek Parnell <derek nomail.afraid.org> wrote:But why templates?!?!? How is that different from ... struct S3 { const(int) member1; const(float) member2; const(bool) member3; } No template involved. I'm reading Walter as saying that if any struct definition involves any of its members being const/invariant, then one must define that struct in terms of templates. Is this what Walter is really saying?In other words, if I have a struct with three members, each of a different type, I need to code ... struct S3(T, U, V) { T member1; U member2; V member3; } S3!(const(int), const(float), const(bool)); and so on for 4, 5, 6, .... 23 member structs. I'm sure I'm misunderstanding you, because this is really silly.I don't think you're misunderstanding. I think that's what Walter is saying.
Sep 12 2007
Derek Parnell wrote:'invariant' = constant 'const' = read-only It's simple I think. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#Do const and invariant now mean "fully const" and "fully invariant", where fully means "head and tail combined":Remind me again what the difference between 'const' and 'invariant' is.
Sep 10 2007
Content-Disposition: inline On 9/11/07, Bruno Medeiros <brunodomedeiros+spam com.gmail> wrote:'invariant' = constant 'const' = read-onlyIt's simple, but - I would argue - the wrong choice. A better choice (in my humble opinion) would be const = constant readonly = read-only If it's not too late to change the keywords, that, to me, would be the way to go.
Sep 11 2007
Content-Disposition: inline On 9/11/07, Janice Caron <caron800 googlemail.com> wrote:It's simple, but - I would argue - the wrong choice. A better choice (in my humble opinion) would be const = constant readonly = read-only If it's not too late to change the keywords, that, to me, would be the way to go.By which I mean, if it's at all feasable to consider ditching the keyword "invariant" altogether, and introducing a new keyword "readonly", then let's do it. "readonly" should indicate a read-only view of data which someone else might modify, and "const" should imply that no-one can modify it ever, no way, nohow. I'm not quite sure why no one before now has suggested using "readonly" to mean read-only and "const" to mean constant, but seems kind of a no-brainer to me. You know - calling a thing what it is, instead of something it's not. I know I'd be dead confused if int meant float, for example.
Sep 11 2007
Janice Caron wrote:On 9/11/07, *Janice Caron* <caron800 googlemail.com <mailto:caron800 googlemail.com>> wrote: It's simple, but - I would argue - the wrong choice. A better choice (in my humble opinion) would be const = constant readonly = read-only If it's not too late to change the keywords, that, to me, would be the way to go. By which I mean, if it's at all feasable to consider ditching the keyword "invariant" altogether, and introducing a new keyword "readonly", then let's do it. "readonly" should indicate a read-only view of data which someone else might modify, and "const" should imply that no-one can modify it ever, no way, nohow. I'm not quite sure why no one before now has suggested using "readonly" to mean read-only and "const" to mean constant, but seems kind of a no-brainer to me. You know - calling a thing what it is, instead of something it's not. I know I'd be dead confused if int meant float, for example.It has been suggested before several times. The problem is there's disagreement over what it should mean. To some it is obvious that "readonly" should mean permanently unwriteable, just like "read only memory" is unwriteable. To others it is equally obvious that it should mean a read-only view of data that is writeable through some other means. --bb
Sep 11 2007
Bill Baxter wrote:Janice Caron wrote:The problem is that, broadly speaking, all these words mean the same thing. Once you get down to splitting hairs over exactly how constant/invariant/immutable/readonly/final something is, you're always going to find some (possibly obscure) argument against the way you want it to work. Aren't natural languages fun?! :P -- DanielOn 9/11/07, *Janice Caron* <caron800 googlemail.com <mailto:caron800 googlemail.com>> wrote: It's simple, but - I would argue - the wrong choice. A better choice (in my humble opinion) would be const = constant readonly = read-only If it's not too late to change the keywords, that, to me, would be the way to go. By which I mean, if it's at all feasable to consider ditching the keyword "invariant" altogether, and introducing a new keyword "readonly", then let's do it. "readonly" should indicate a read-only view of data which someone else might modify, and "const" should imply that no-one can modify it ever, no way, nohow. I'm not quite sure why no one before now has suggested using "readonly" to mean read-only and "const" to mean constant, but seems kind of a no-brainer to me. You know - calling a thing what it is, instead of something it's not. I know I'd be dead confused if int meant float, for example.It has been suggested before several times. The problem is there's disagreement over what it should mean. To some it is obvious that "readonly" should mean permanently unwriteable, just like "read only memory" is unwriteable. To others it is equally obvious that it should mean a read-only view of data that is writeable through some other means. --bb
Sep 11 2007
On Tue, 11 Sep 2007 19:10:29 +1000, Daniel Keep wrote:Bill Baxter wrote:Therefore let's invent some new keywords, ones that are unlikely to clash with user declared identifiers ... I'll start this ball rolling. 'rodata' instead of 'invariant' (Read Only Data) 'roview' instead of 'const' (Read Only View) alias string rodata(char)[]; -- Derek Parnell Melbourne, Australia skype: derek.j.parnellJanice Caron wrote:The problem is that, broadly speaking, all these words mean the same thing. Once you get down to splitting hairs over exactly how constant/invariant/immutable/readonly/final something is, you're always going to find some (possibly obscure) argument against the way you want it to work. Aren't natural languages fun?!On 9/11/07, *Janice Caron* <caron800 googlemail.com <mailto:caron800 googlemail.com>> wrote: It's simple, but - I would argue - the wrong choice. A better choice (in my humble opinion) would be const = constant readonly = read-only If it's not too late to change the keywords, that, to me, would be the way to go. By which I mean, if it's at all feasable to consider ditching the keyword "invariant" altogether, and introducing a new keyword "readonly", then let's do it. "readonly" should indicate a read-only view of data which someone else might modify, and "const" should imply that no-one can modify it ever, no way, nohow. I'm not quite sure why no one before now has suggested using "readonly" to mean read-only and "const" to mean constant, but seems kind of a no-brainer to me. You know - calling a thing what it is, instead of something it's not. I know I'd be dead confused if int meant float, for example.It has been suggested before several times. The problem is there's disagreement over what it should mean. To some it is obvious that "readonly" should mean permanently unwriteable, just like "read only memory" is unwriteable. To others it is equally obvious that it should mean a read-only view of data that is writeable through some other means. --bb
Sep 11 2007
Content-Disposition: inlineTherefore let's invent some new keywords, ones that are unlikely to clash with user declared identifiers ...Coined words! Wow - now there's a thought! brillig = invariant data slithy = head const mimsy = read-only view ...with apologies to Lewis Carroll And that would give us lots of other lovely keywords to play with! Oh my - frumious, vorpal, uffish, whiffling, tulgey. The possibilities are boundless! O frabjous day! /* This post is in jest */
Sep 11 2007
Daniel Keep wrote:They are. The meaning of words is very domain dependent is often based on convention rather than anything else. I am sorry, but I can't pass this chance to present my side of the argument once more. :) To an electrical engineer, "read-only" will surely give an association of memory that is "hard to change quickly or easily" (wikipedia), or maybe read-only pins, or read-only registers. To a mathematician, "constant" is a fixed value, the opposite of a "variable". In computer science, read-only could have a number of meanings. The top search results on citeseer for read-only yields the following terms: * read-only transactions * read-only memory * read-only file system * read-only query * read-only fields * read-only methods * read-only replication * read-only access * read-only parameters * read-only actions * read-only state * read-only optimizations * read-only file of which "read-only memor(y|ies)" corresponds to a mere 3.7 % of the papers, while "read-only transaction(|s)" corresponds to 29 %. The prevailing meaning of read-only in CS seems to be that in regard to access. Using read-only in the meaning of access will also not conflict with existing uses (even for an electrical engineer). On the other hand, using "const"(ant) in the meaning of something that may change, or is only access protected does conflict with the mathematical definition. It is therefore, in my view, obvious that substituting the words (readonly,const) for todays (const,invariant) would result in a much better match between the semantics of D and that of established and natural languages. The crucial separation here is: * read-only -> access * constant -> data Does the following conversation make sense? A: "I have a function that requires a read-only reference to some data" B: "Fine, I can use it for both my variable and my constant data" -- OskarJanice Caron wrote:The problem is that, broadly speaking, all these words mean the same thing. Once you get down to splitting hairs over exactly how constant/invariant/immutable/readonly/final something is, you're always going to find some (possibly obscure) argument against the way you want it to work. Aren't natural languages fun?!It's simple, but - I would argue - the wrong choice. A better choice (in my humble opinion) would be const = constant readonly = read-only
Sep 11 2007
Oskar Linde wrote:Daniel Keep wrote:I agree. (Damn, I always agree with you Oskar :P ) But I'll add: It's not just that the "read-only" meaning as in "read-only access/permissions" is the most popular one. It's also the meaning most congruent with the natural language term "read-only". That is, it's the most "meaningful". ROM memory "is" read-only in the same sense that a dear is mammal. A deer is indeed a mammal, but it's more than a mammal, it's... a deer. :P It's likely due to that that the alternative terminology wouldn't sound so strange for an electrical engineer, while the current one sounds strange for (most of) us CS programmers. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DThey are. The meaning of words is very domain dependent is often based on convention rather than anything else. I am sorry, but I can't pass this chance to present my side of the argument once more. :) To an electrical engineer, "read-only" will surely give an association of memory that is "hard to change quickly or easily" (wikipedia), or maybe read-only pins, or read-only registers. To a mathematician, "constant" is a fixed value, the opposite of a "variable". In computer science, read-only could have a number of meanings. The top search results on citeseer for read-only yields the following terms: * read-only transactions * read-only memory * read-only file system * read-only query * read-only fields * read-only methods * read-only replication * read-only access * read-only parameters * read-only actions * read-only state * read-only optimizations * read-only file of which "read-only memor(y|ies)" corresponds to a mere 3.7 % of the papers, while "read-only transaction(|s)" corresponds to 29 %. The prevailing meaning of read-only in CS seems to be that in regard to access. Using read-only in the meaning of access will also not conflict with existing uses (even for an electrical engineer). On the other hand, using "const"(ant) in the meaning of something that may change, or is only access protected does conflict with the mathematical definition. It is therefore, in my view, obvious that substituting the words (readonly,const) for todays (const,invariant) would result in a much better match between the semantics of D and that of established and natural languages. The crucial separation here is: * read-only -> access * constant -> data Does the following conversation make sense? A: "I have a function that requires a read-only reference to some data" B: "Fine, I can use it for both my variable and my constant data"Janice Caron wrote:The problem is that, broadly speaking, all these words mean the same thing. Once you get down to splitting hairs over exactly how constant/invariant/immutable/readonly/final something is, you're always going to find some (possibly obscure) argument against the way you want it to work. Aren't natural languages fun?!It's simple, but - I would argue - the wrong choice. A better choice (in my humble opinion) would be const = constant readonly = read-only
Sep 11 2007
Janice Caron wrote:I'm not quite sure why no one before now has suggested using "readonly" to mean read-only and "const" to mean constant, but seems kind of a no-brainer to me. You know - calling a thing what it is, instead of something it's not. I know I'd be dead confused if int meant float, for example.It was quite naive to think that no one had suggested keyword changes for this before. :P -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Sep 11 2007
Content-Disposition: inline I always think of "read only" as meaning "a read only VIEW". Examples abound: e.g. opening a file in read-only mode. Even the read-only attribute of a file (which you can change). Still - another keyword you might consider appropriate to the meaning "read only view" is "in". Now there's a thought; Oh - and here's something else I'd like to be able to do. Instead of: class C { private int my_n; public int n() { return my_n; } /* all my private code refers to my_n */ } I'd like to be able to do class C { (privately read-write but publicly read-only) int n; /* all my private code refers to n */ } That would be cool. Thanks
Sep 11 2007
On Tue, 11 Sep 2007 12:09:21 +0100, Janice Caron wrote:class C { private int my_n; public int n() { return my_n; } /* all my private code refers to my_n */ } } I'd like to be able to do class C { (privately read-write but publicly read-only) int n; /* all my private code refers to n */ } }This would translate to something else coming from Delphi, the "property" tag with the read and write options. You could easily translate this to a D-ish way: private { int my_n; } public { property int my_n: read my_n; } so, whenever you're inside your class, you always have the reference onto the private member. Whenever wanting to read the value of my_n from outside the class, you will get the public member that is just a "wrapper" to the internal one. But that would make it possible for something like: private { int my_n; int get_my_n () { // do some calculation that may change the responded value of my_n, // for example the object wanting to have the information return theCorrectValue; } void set_my_n () { // do some calculation, check the range, whatever my_n = theCorrectValue; } } public { property int my_n: read get_my_n write set_my_n } Well this looks like a Delphi declaration with C Syntax, so i I guess it might not make it into D ;-) Apart from that it would cover your problem with "internal RW-access, external R-access only". -- .71 nicolai dot waniek at sphere71 dot com
Sep 11 2007
Content-Disposition: inline On 9/11/07, Nicolai Waniek <nospam inval.id> wrote:Apart from that it would cover your problem with "internal RW-access, external R-access only".I think you may have missed the point there. We can already do that with D. I /have/ no problem with "internal RW-access, external R-access only". There is no problem to solve. Nonetheless, it would still be cool if there were a new keyword or some other way to mean: privately_readwrite_but_publicly_readonly int x; See? I already know how to do it without the "privately_readwrite_but_publicly_readonly" keyword.
Sep 11 2007
Bruno Medeiros wrote:Derek Parnell wrote:I must withdraw somewhat my comment that "it's simple", since "read-only" is indeed a somewhat subjective term. If you think read-only as in permissions, you get the intended meaning. But if you think read-only as in memory (ROM), as Bill mentioned, you get the same meaning as constant. Still, I think the "read-only as in permissions" meaning for "read-only" is becoming more prevalent as it is more... meaningful. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D'invariant' = constant 'const' = read-only It's simple I think.o const and invariant now mean "fully const" and "fully invariant", where fully means "head and tail combined":Remind me again what the difference between 'const' and 'invariant' is.
Sep 11 2007
Oh wait! I do have one comment, or question, or whatever.const int* p = &x; // neither p nor *p can be changed const(int*) p = &x; // neither p nor *p can be changedTwo ways of writing the same thing. I don't understand the need for the bracketless version. Could we not just insist that the brackets must always be there? Or does the lack of brackets actually mean something? (if it does, it's back to being confusing again).
Sep 10 2007
Janice Caron wrote:Oh wait! I do have one comment, or question, or whatever.I thought the same thing. I suspect the brackets will remain optional, but I reckon "good style" would require them. For clarity if nothing else. Reganconst int* p = &x; // neither p nor *p can be changed const(int*) p = &x; // neither p nor *p can be changedTwo ways of writing the same thing. I don't understand the need for the bracketless version. Could we not just insist that the brackets must always be there? Or does the lack of brackets actually mean something? (if it does, it's back to being confusing again).
Sep 10 2007
Oh wait! I do have one comment, or question, or whatever.const int* p = &x; // neither p nor *p can be changed const(int*) p = &x; // neither p nor *p can be changedTwo ways of writing the same thing. I don't understand the need for the bracketless version. Could we not just insist that the brackets must always be there? Or does the lack of brackets actually mean something? (if it does, it's back to being confusing again).
Sep 10 2007
Janice Caron wrote:Oh wait! I do have one comment, or question, or whatever.I'd rather have the bracketless version to save typing in the case when I want to have the whole thing be const (which is the most common case, I believe). Thanks, Nathan Reedconst int* p = &x; // neither p nor *p can be changed const(int*) p = &x; // neither p nor *p can be changedTwo ways of writing the same thing. I don't understand the need for the bracketless version. Could we not just insist that the brackets must always be there? Or does the lack of brackets actually mean something? (if it does, it's back to being confusing again).
Sep 10 2007
Janice Caron wrote:The bracketless version is for two reasons: 1) it's what people expect to have to type, for example: void foo(const T t) { } It will be the most common case. 2) it enables things like: const { int a = 3; int b = 4; } which is nice for a grouped collection of them.const int* p = &x; // neither p nor *p can be changed const(int*) p = &x; // neither p nor *p can be changedTwo ways of writing the same thing. I don't understand the need for the bracketless version. Could we not just insist that the brackets must always be there? Or does the lack of brackets actually mean something? (if it does, it's back to being confusing again).
Sep 10 2007
Walter Bright escribió:Const, final, invariant, head const, tail const, it's grown into a monster. It tries to cover all the bases, but in doing so is simply not understandable. Andrei and Bartosz have spent some time together going back to square one with what are we trying to achieve with const, and came up with another proposal. What we are trying to achieve: a) utility for functional programming b) better modularity by self-documenting interfaces better c) be able to treat reference types as if they were value types (i.e. strings should behave to the user like value types, even though they are references) The insights they came up with were: 1) final (i.e. 'head const') is not necessary for a, b or c. final is a local thing, and not strictly necessary. 2) tail const can be handled in other ways, read on So, what we are left with is: o no more final o const and invariant now mean "fully const" and "fully invariant", where fully means "head and tail combined": const int x = 0; // x is constant const int* p = &x; // neither p nor *p can be changed const(int*) p = &x; // neither p nor *p can be changed const(int)* p = &x; // p can change, *p cannot be changed o const and invariant are transitive. There is no way to specify a (pointer to)(const pointer to)(mutable int). o tail invariant for an array or pointer type can be done using the existing syntax: invariant(char)[] s; // string, i.e. an array of invariant chars const(T)* p; // pointer to tail const T o tail const of a struct would have to be done by making the struct a template: struct S(T) { T member; } S!(int) // tail mutable S!(const(int)) // tail const o one can construct a template to generically produce tail const or tail invariant versions of a type. o it will be illegal to attempt to change the key value of a foreach loop, but the compiler will not be able to diagnose all attempts to do so o static const/invariant means the initializer is evaluated at compile time. non-static const/invariant means it is evaluated at run time. o no initializer means it is assigned in the corresponding constructor. o const/invariant declarations will always allocate memory (so their addresses can be taken)I won't comment on all that since I'm still lost in all that const thing. But...o So, we still need a method to declare a constant that will not consume memory. We'll co-opt the future macro syntax for that: macro x = 3; macro s = "hello";Am I the only one who doesn't like this syntax? I guess it kinda makes sense, but I just don't like how it looks. -- Carlos Santander Bernal
Sep 10 2007
Carlos Santander wrote:Walter Bright escribió:Seems to me like this unnecessarily departs from the macro syntax introduced at the conference: macro foo(e) { e = 3; } (On the other hand, in one of them the macro is for an expression while in the other one it's a sequence of declarations/statements. So maybe it is reasonable to have the different syntax.) Thanks, Nathan Reedo So, we still need a method to declare a constant that will not consume memory. We'll co-opt the future macro syntax for that: macro x = 3; macro s = "hello";Am I the only one who doesn't like this syntax? I guess it kinda makes sense, but I just don't like how it looks.
Sep 10 2007
Nathan Reed wrote:Carlos Santander wrote:It's not far off from things used in some functional programming languages, so it doesn't look to bad to me. The word 'macro' typically implies a direct, maybe even textual, substitution. It's also a lot like #define, just with an '=' there which I think is an improvement over #define. '=' for the no-arg macros, '{ }' for the arg-ful macros. Seems ok to me. --bbWalter Bright escribió:Seems to me like this unnecessarily departs from the macro syntax introduced at the conference: macro foo(e) { e = 3; } (On the other hand, in one of them the macro is for an expression while in the other one it's a sequence of declarations/statements. So maybe it is reasonable to have the different syntax.)o So, we still need a method to declare a constant that will not consume memory. We'll co-opt the future macro syntax for that: macro x = 3; macro s = "hello";Am I the only one who doesn't like this syntax? I guess it kinda makes sense, but I just don't like how it looks.
Sep 10 2007
Bill Baxter wrote:Nathan Reed wrote:And let's take another step forward (might scare off some old C farts, though, but I like it): T sum(T)(T a, T b) = a + b; For consistency's sake! :DCarlos Santander wrote:It's not far off from things used in some functional programming languages, so it doesn't look to bad to me. The word 'macro' typically implies a direct, maybe even textual, substitution. It's also a lot like #define, just with an '=' there which I think is an improvement over #define. '=' for the no-arg macros, '{ }' for the arg-ful macros. Seems ok to me.Walter Bright escribió:Seems to me like this unnecessarily departs from the macro syntax introduced at the conference: macro foo(e) { e = 3; } (On the other hand, in one of them the macro is for an expression while in the other one it's a sequence of declarations/statements. So maybe it is reasonable to have the different syntax.)o So, we still need a method to declare a constant that will not consume memory. We'll co-opt the future macro syntax for that: macro x = 3; macro s = "hello";Am I the only one who doesn't like this syntax? I guess it kinda makes sense, but I just don't like how it looks.
Sep 10 2007
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Jari-Matti Mäkelä wrote:Bill Baxter wrote:How about so? T sum(T)(T a, T b) a + b; This contains two things that I've feature requested before: implicit return of the last expression in a function, and omitting { } for one-statement functions. My point being, it's somewhat closer to our current D than your approach, in that it only requires two backwards-compatible extensions instead of a whole new syntax :) --downs -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFG5daKpEPJRr05fBERApOlAJ9+t/uJ1CskJhPikz/ni1SqgT/fkgCeO/yG lFhsq9awCy0Gi1fSTUNBWU4= =pA1m -----END PGP SIGNATURE-----Nathan Reed wrote:And let's take another step forward (might scare off some old C farts, though, but I like it): T sum(T)(T a, T b) = a + b; For consistency's sake! :DCarlos Santander wrote:It's not far off from things used in some functional programming languages, so it doesn't look to bad to me. The word 'macro' typically implies a direct, maybe even textual, substitution. It's also a lot like #define, just with an '=' there which I think is an improvement over #define. '=' for the no-arg macros, '{ }' for the arg-ful macros. Seems ok to me.Walter Bright escribió:Seems to me like this unnecessarily departs from the macro syntax introduced at the conference: macro foo(e) { e = 3; } (On the other hand, in one of them the macro is for an expression while in the other one it's a sequence of declarations/statements. So maybe it is reasonable to have the different syntax.)o So, we still need a method to declare a constant that will not consume memory. We'll co-opt the future macro syntax for that: macro x = 3; macro s = "hello";Am I the only one who doesn't like this syntax? I guess it kinda makes sense, but I just don't like how it looks.
Sep 10 2007
Carlos Santander Wrote:Walter Bright escribió:[snip]Const, final, invariant, head const, tail const, it's grown into a monster. It tries to cover all the bases, but in doing so is simply not understandable.I'm not clear why this is even needed. Surely "static const" implies some level of don't consume any memory by virtue of meaning "available at compile time". If you need more than that, rather than trusting the compiler then I second "inline" rather than macro, but honestly I can't think of an example where this will give you a worthwhile performance gain (unlike an inline function). Regards, Bruce.o So, we still need a method to declare a constant that will not consume memory. We'll co-opt the future macro syntax for that: macro x = 3; macro s = "hello";Am I the only one who doesn't like this syntax? I guess it kinda makes sense, but I just don't like how it looks. -- Carlos Santander Bernal
Sep 10 2007
Bruce Adams wrote:windows.h in all its terrifying glory has 10,000 macro declarations. If each one occupied 4 bytes of static data, there's 40K of bloat in every exe.I'm not clear why this is even needed. Surely "static const" implies some level of don't consume any memory by virtue of meaning "available at compile time". If you need more than that, rather than trusting the compiler then I second "inline" rather than macro, but honestly I can't think of an example where this will give you a worthwhile performance gain (unlike an inline function).o So, we still need a method to declare a constant that will not consume memory. We'll co-opt the future macro syntax for that: macro x = 3; macro s = "hello";
Sep 10 2007
Walter Bright wrote:Bruce Adams wrote:That sounds about right. When we converted const values to enum values in the Tango Win32 headers, app size dropped by roughly 46k. But there were issues with some of those enum values having the wrong type (-1 set to int instead of uint), which led to a few strange bugs. Seanwindows.h in all its terrifying glory has 10,000 macro declarations. If each one occupied 4 bytes of static data, there's 40K of bloat in every exe.I'm not clear why this is even needed. Surely "static const" implies some level of don't consume any memory by virtue of meaning "available at compile time". If you need more than that, rather than trusting the compiler then I second "inline" rather than macro, but honestly I can't think of an example where this will give you a worthwhile performance gain (unlike an inline function).o So, we still need a method to declare a constant that will not consume memory. We'll co-opt the future macro syntax for that: macro x = 3; macro s = "hello";
Sep 10 2007
Sean Kelly Wrote:Walter Bright wrote:I seek enlightenmnet for at least two problems with that explanation. windows.h is a C binding not a D binding. I'm not clear how one translates to the other yet as I've avoided bi-lingual stuff so far. Presumably the D binding is created using htod. I thought D followed the you only pay for what you use philosophy. So if I import my windows.d module I will only pay the cost of the variables I actually use. My friendly neighbourhoold compiler, being clever, mightl also make an effort to minimise the cost of those too. While we're on the subject of windows. 40K means nothing. In an embedded system yes. Windows is bloated to the point where 40K in a user application means de nada. (I shudder at the 4Gb games that follow in its wake too). I have know idea where the windows mobile / CE / pocket PC api falls here. Regards, Bruce.Bruce Adams wrote:That sounds about right. When we converted const values to enum values in the Tango Win32 headers, app size dropped by roughly 46k. But there were issues with some of those enum values having the wrong type (-1 set to int instead of uint), which led to a few strange bugs. Seanwindows.h in all its terrifying glory has 10,000 macro declarations. If each one occupied 4 bytes of static data, there's 40K of bloat in every exe.I'm not clear why this is even needed. Surely "static const" implies some level of don't consume any memory by virtue of meaning "available at compile time". If you need more than that, rather than trusting the compiler then I second "inline" rather than macro, but honestly I can't think of an example where this will give you a worthwhile performance gain (unlike an inline function).o So, we still need a method to declare a constant that will not consume memory. We'll co-opt the future macro syntax for that: macro x = 3; macro s = "hello";
Sep 10 2007
Bruce Adams wrote:Sean Kelly Wrote:htod works for simple cased. More complex cases require GregorR's BCD or simply a manual effort.Walter Bright wrote:I seek enlightenmnet for at least two problems with that explanation. windows.h is a C binding not a D binding. I'm not clear how one translates to the other yet as I've avoided bi-lingual stuff so far. Presumably the D binding is created using htod.Bruce Adams wrote:That sounds about right. When we converted const values to enum values in the Tango Win32 headers, app size dropped by roughly 46k. But there were issues with some of those enum values having the wrong type (-1 set to int instead of uint), which led to a few strange bugs. Seanwindows.h in all its terrifying glory has 10,000 macro declarations. If each one occupied 4 bytes of static data, there's 40K of bloat in every exe.I'm not clear why this is even needed. Surely "static const" implies some level of don't consume any memory by virtue of meaning "available at compile time". If you need more than that, rather than trusting the compiler then I second "inline" rather than macro, but honestly I can't think of an example where this will give you a worthwhile performance gain (unlike an inline function).o So, we still need a method to declare a constant that will not consume memory. We'll co-opt the future macro syntax for that: macro x = 3; macro s = "hello";I thought D followed the you only pay for what you use philosophy. So if I import my windows.d module I will only pay the cost of the variables I actually use. My friendly neighbourhoold compiler, being clever, mightl also make an effort to minimise the cost of those too.D currently links at the file level, so if you use anything in a file you get the whole thing. Some linkers are able to link at the section level (a piece of a file), but D does not support this yet (see comments regarding gc-sections using ld, I believe--there's an issue in BugTracker about this).While we're on the subject of windows. 40K means nothing. In an embedded system yes. Windows is bloated to the point where 40K in a user application means de nada. (I shudder at the 4Gb games that follow in its wake too). I have know idea where the windows mobile / CE / pocket PC api falls here.It matters to some people, particularly those coming from C and comparing EXE sizes. It may not be relevant as far as general development on Windows is concerned, but it's something library developers must take into consideration. Sean
Sep 11 2007
Walter Bright wrote:(snip) o static const/invariant means the initializer is evaluated at compile time. non-static const/invariant means it is evaluated at run time.I'd like to suggest that we use some keyword other than "static." Yeah, I know that "static" can imply "static analysis" (compile time), but the static modifier on a variable has a well-known meaning from C: it's not exported. I think that that was a poor design choice in C, but now we're stuck with millions of programmers who expect it. I think that this would just cause confusion, and perhaps we need a new keyword to express this new concept. While I understand that we don't want to multiply keywords, multiplying concepts, and then overloading them all into a single keyword, is, IMHO, even worse.o no initializer means it is assigned in the corresponding constructor. o const/invariant declarations will always allocate memory (so their addresses can be taken) o So, we still need a method to declare a constant that will not consume memory. We'll co-opt the future macro syntax for that: macro x = 3; macro s = "hello";How about "inline"? That seems to clearly express what we want to express (there is a clear parallel between inline functions and inline constants). I don't recall: is inline a keyword in D or not?
Sep 10 2007
On 9/10/07, Russell Lewis <webmaster villagersonline.com> wrote:the static modifier on a variable has a well-known meaning from C: it's not exported.We use private for that purpose in D, so static is free to be retooled to mean "compile-time".
Sep 10 2007
Russell Lewis wrote:Walter Bright wrote: > (snip)No one cares (or at least, should care) what that means in C. That's ancient history. More important is the other meaning that 'static' in *D itself*: the meaning of "non-instance / unique" which is really unrelated to "compile-time". -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#Do static const/invariant means the initializer is evaluated at compile time. non-static const/invariant means it is evaluated at run time.I'd like to suggest that we use some keyword other than "static." Yeah, I know that "static" can imply "static analysis" (compile time), but the static modifier on a variable has a well-known meaning from C: it's not exported. I think that that was a poor design choice in C, but now we're stuck with millions of programmers who expect it.
Sep 10 2007
Walter Bright wrote:Const, final, invariant, head const, tail const, it's grown into a monster. It tries to cover all the bases, but in doing so is simply not understandable. Andrei and Bartosz have spent some time together going back to square one with what are we trying to achieve with const, and came up with another proposal. What we are trying to achieve: a) utility for functional programming b) better modularity by self-documenting interfaces better c) be able to treat reference types as if they were value types (i.e. strings should behave to the user like value types, even though they are references)Does c) include being able to pass literal arguments to functions expecting const-references? I.e. sort of the opposite: being able to treat value types as const-references, even though they are const values.o const and invariant now mean "fully const" and "fully invariant", where fully means "head and tail combined": const int x = 0; // x is constant const int* p = &x; // neither p nor *p can be changed const(int*) p = &x; // neither p nor *p can be changed const(int)* p = &x; // p can change, *p cannot be changedI'm very happy that 'const int' will mean something other than 'just plain int'. The always-off-by-one part of the current design is hard to get enthusiastic about. But this one makes more sense. Maybe you might consider Janice's suggestion for the structs, though: const(S)* // Pointer to S nonconst, S is const const(S) // S const const*(S) // S nonconst, but stuff accessed via S is const const**(S) // S and S.member nonconst, but stuff accessed via S.member is const --bb
Sep 10 2007
Walter Bright wrote:What we are trying to achieve: a) utility for functional programming b) better modularity by self-documenting interfaces better c) be able to treat reference types as if they were value types (i.e. strings should behave to the user like value types, even though they are references)Is there a way to express (for a pointer passed as a function parameter) "the callee is allowed to modify this object through the pointer, but the caller ensures that no other code will be modifying it at the same time"? Sort of a "you have exclusive write access" modifier? Is that a common enough case to even support? Russ
Sep 10 2007
Russell Lewis wrote:Walter Bright wrote:It would probably be easy enough to add such a type modifier, but literally impossible to to hold that restriction, so I don't think it's worth it. There's no magic-bullet for concurrency. - Gregor RichardsWhat we are trying to achieve: a) utility for functional programming b) better modularity by self-documenting interfaces better c) be able to treat reference types as if they were value types (i.e. strings should behave to the user like value types, even though they are references)Is there a way to express (for a pointer passed as a function parameter) "the callee is allowed to modify this object through the pointer, but the caller ensures that no other code will be modifying it at the same time"? Sort of a "you have exclusive write access" modifier? Is that a common enough case to even support? Russ
Sep 10 2007
Gregor Richards wrote:Russell Lewis wrote:I agree that there's no magic-bullet for concurrency, but there *are* times where it could be enforced: 1) The caller's variable is a local variable, and either there have been no pointers to the local (including frame pointers created by delegate literals), or else all of those locals were passed to external code as "const." 2) The caller already holds the variable in "exclusive" mode. (I haven't figured out any way, yet, to make it work for globals.) Whether it's worth the trouble is a whole 'nother question, of course.Walter Bright wrote:It would probably be easy enough to add such a type modifier, but literally impossible to to hold that restriction, so I don't think it's worth it. There's no magic-bullet for concurrency.What we are trying to achieve: a) utility for functional programming b) better modularity by self-documenting interfaces better c) be able to treat reference types as if they were value types (i.e. strings should behave to the user like value types, even though they are references)Is there a way to express (for a pointer passed as a function parameter) "the callee is allowed to modify this object through the pointer, but the caller ensures that no other code will be modifying it at the same time"? Sort of a "you have exclusive write access" modifier? Is that a common enough case to even support? Russ
Sep 10 2007
Russell Lewis wrote:Walter Bright wrote:That's sort of what the often proposed 'unique' type qualifier does. The problem is, there's just no reasonable way to implement it in a *checkable* manner. And if it ain't checkable, it's about as useful as painting a black stripe across your lap when driving instead of wearing a seatbelt.What we are trying to achieve: a) utility for functional programming b) better modularity by self-documenting interfaces better c) be able to treat reference types as if they were value types (i.e. strings should behave to the user like value types, even though they are references)Is there a way to express (for a pointer passed as a function parameter) "the callee is allowed to modify this object through the pointer, but the caller ensures that no other code will be modifying it at the same time"? Sort of a "you have exclusive write access" modifier? Is that a common enough case to even support?
Sep 10 2007
Walter Bright Wrote:Russell Lewis wrote:I see a least two ways of interpreting it at run-time. Acquire a lock before entering the function (or at least the parts where the value is modified) or in an STM atomic transaction roll-back and try again if the value is modified. Being run-time only I suspect a function or template and lazy evaluation might suffice. At compile time you could use it as a hint for 'linting' race conditions out of your code. That is a useful instrumentation to have. (cyclist wearing a flourescent band as opposed to a black stripe) These are just suggestions I wouldn't advocate anything without more thought. As I said on the next branch over this is off topic for a discussion about const. Regards, Bruce.Walter Bright wrote:That's sort of what the often proposed 'unique' type qualifier does. The problem is, there's just no reasonable way to implement it in a *checkable* manner. And if it ain't checkable, it's about as useful as painting a black stripe across your lap when driving instead of wearing a seatbelt.What we are trying to achieve: a) utility for functional programming b) better modularity by self-documenting interfaces better c) be able to treat reference types as if they were value types (i.e. strings should behave to the user like value types, even though they are references)Is there a way to express (for a pointer passed as a function parameter) "the callee is allowed to modify this object through the pointer, but the caller ensures that no other code will be modifying it at the same time"? Sort of a "you have exclusive write access" modifier? Is that a common enough case to even support?
Sep 10 2007
Walter Bright wrote:Russell Lewis wrote:Except for the most pathological cases, I believe there are some checkable ways to do this. Consider a piece of code that uniquely has write privilege to a variable (and is only ever called from a specific thread). In that case, it can give out scoped invariant access when calling functions within its thread, or const access to anything. Violation of the unique write privilege should be easy enough to check/enforce. For example, calling a function (or passing a delegate) with non-const access. Of course, this all relies on avoiding multi-threaded calls to a function. While I haven't thought it all out, I think the answer may lie with thread-local storage.Walter Bright wrote:That's sort of what the often proposed 'unique' type qualifier does. The problem is, there's just no reasonable way to implement it in a *checkable* manner. And if it ain't checkable, it's about as useful as painting a black stripe across your lap when driving instead of wearing a seatbelt.What we are trying to achieve: a) utility for functional programming b) better modularity by self-documenting interfaces better c) be able to treat reference types as if they were value types (i.e. strings should behave to the user like value types, even though they are references)Is there a way to express (for a pointer passed as a function parameter) "the callee is allowed to modify this object through the pointer, but the caller ensures that no other code will be modifying it at the same time"? Sort of a "you have exclusive write access" modifier? Is that a common enough case to even support?
Sep 10 2007
Jason House wrote:Except for the most pathological cases...The pathological case that I'm aware of is recursion.
Sep 10 2007
Jason House Wrote:Jason House wrote:[OT] recursion is an odd beast. Its a fundermental programming concept and yet I noticed recently that I almost never ever need it in C++. In fact it only seems to come up in templates. In D we have static looping constructs which remove the need even there. I wonder how often it will show up in practice. Bruce.Except for the most pathological cases...The pathological case that I'm aware of is recursion.
Sep 11 2007
Russell Lewis Wrote:Walter Bright wrote:That's an interesting concept. From the functions point of view it would compile as if it was invariant but the invariantness doesn't have a lifetime beyond the function. I think its slightly off topic here though, multi-threading / IPC is an entirely different kettle of bananas. How do you even declare whether a variable is shared or thread-local at the moment? This is only indirectly related to the const concept. What we have hear is "shared locked" versus "shared volatile" versus "local". Bruce.What we are trying to achieve: a) utility for functional programming b) better modularity by self-documenting interfaces better c) be able to treat reference types as if they were value types (i.e. strings should behave to the user like value types, even though they are references)Is there a way to express (for a pointer passed as a function parameter) "the callee is allowed to modify this object through the pointer, but the caller ensures that no other code will be modifying it at the same time"? Sort of a "you have exclusive write access" modifier? Is that a common enough case to even support? Russ
Sep 10 2007
Walter Bright wrote:Const, final, invariant, head const, tail const, it's grown into a monster. It tries to cover all the bases, but in doing so is simply not understandable.Took you guys a while to figure that out... -_-'1) final (i.e. 'head const') is not necessary for a, b or c. final is a local thing, and not strictly necessary.Then, there will no longer be a final "storage class" for var declarations?2) tail const can be handled in other ways, read on[...]o tail const of a struct would have to be done by making the struct a template: struct S(T) { T member; } S!(int) // tail mutable S!(const(int)) // tail const o one can construct a template to generically produce tail const or tail invariant versions of a type.As Regan asked before, and how would that work for classes? This is a most fundamental issue that has not been mentioned. Without a way to declare tail const/invariant, this design, no matter how simpler or more understandable, is fundamentally *broken*. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Sep 10 2007
Bruno Medeiros wrote:As Regan asked before, and how would that work for classes? This is a most fundamental issue that has not been mentioned. Without a way to declare tail const/invariant, this design, no matter how simpler or more understandable, is fundamentally *broken*.What, exactly, is the use case that needs a solution?
Sep 10 2007
Walter Bright wrote:Bruno Medeiros wrote:Before hand, let me just say that by broken, I didn't mean subvertable, but rather that using const/invariant with classes would be impractical and unmanageable. Simple example: Let's say you have a class Foo that is comparable. How do you sort an array of const(Foo)'s ? const(Foo)[] sort(const(Foo)[] arr) { ... ? The sorting algorithm doesn't matter, what matters is: how would one swap two elements in the array? -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DAs Regan asked before, and how would that work for classes? This is a most fundamental issue that has not been mentioned. Without a way to declare tail const/invariant, this design, no matter how simpler or more understandable, is fundamentally *broken*.What, exactly, is the use case that needs a solution?
Sep 10 2007
Bruno Medeiros wrote:Walter Bright wrote:You can't sort an (array of)(const T). You can sort an (array of)(something of)(const T).What, exactly, is the use case that needs a solution?Before hand, let me just say that by broken, I didn't mean subvertable, but rather that using const/invariant with classes would be impractical and unmanageable. Simple example: Let's say you have a class Foo that is comparable. How do you sort an array of const(Foo)'s ? const(Foo)[] sort(const(Foo)[] arr) { ... ? The sorting algorithm doesn't matter, what matters is: how would one swap two elements in the array?
Sep 10 2007
Walter Bright Wrote:Bruno Medeiros wrote:That worries me (not that case in particular, but general constness + classes). My coding style tends to use a lot of invariant objects (for thread safety reasons), so I get the feeling that the inability to *easily* express a mutable reference to a constant class will bite me like a ferret.Walter Bright wrote:You can't sort an (array of)(const T). You can sort an (array of)(something of)(const T).What, exactly, is the use case that needs a solution?Before hand, let me just say that by broken, I didn't mean subvertable, but rather that using const/invariant with classes would be impractical and unmanageable. Simple example: Let's say you have a class Foo that is comparable. How do you sort an array of const(Foo)'s ? const(Foo)[] sort(const(Foo)[] arr) { ... ? The sorting algorithm doesn't matter, what matters is: how would one swap two elements in the array?
Sep 10 2007
Robert Fraser wrote:That worries me (not that case in particular, but general constness + classes). My coding style tends to use a lot of invariant objects (for thread safety reasons), so I get the feeling that the inability to *easily* express a mutable reference to a constant class will bite me like a ferret.It worries me in the abstract, but I've not been able to find a real case where it matters.
Sep 10 2007
Walter Bright Wrote:Robert Fraser wrote:Here's an easy one: returning constant class references from an opApply. Or, if you argue the variable holding the references is reassigned each time, how about iterating through constant nodes in a linked list? const(node) current; while(current = current.next) { .... } ... or really any sort of iteration using the same variable. Or how about (took looking at half a page of code to find an example similar to this): const(Foo) foo = bar(); if(null is foo) foo = new Foo(); Obviously, there may be a way around this, but I use this idiom fairly frequently, especially when getting stuff that might or might not be in an associative array/map. ... Or what about cached objects, which are passed to the function handling the cache as const (since the function handling the cache shouldn't be changing them), but the references the cache holds are constantly changing? ... I could go on all day like this. Not that any of these are insurmountable (I'd just stop using const for class references altogether and cast when I was sending stuff to a library that wanted it, so there's a way to surmount it in my own code), but to make const usable, these cases need to be considered. In fact, for curiosity's sake, I just ran Eclipse's "use final when possible" on Descent's (incomplete) Java port of the DMD front-end, and it looks like a little more than _half_ of the class references were reassigned sometime during their lifespan. None of these class references could be made to point to constant data.That worries me (not that case in particular, but general constness + classes). My coding style tends to use a lot of invariant objects (for thread safety reasons), so I get the feeling that the inability to *easily* express a mutable reference to a constant class will bite me like a ferret.It worries me in the abstract, but I've not been able to find a real case where it matters.
Sep 10 2007
Walter Bright wrote:Bruno Medeiros wrote:I may be misunderstanding this. When you declare an array const(C)[] where C is a class type, it's really an array of *references* to objects (of class C), right? So it seems unreasonable to restrict such an array from being sorted, since you can sort the references without modifying the objects' contents. In general, I'd think there would be lots of situations where you want to be able to hold a reference to an object, through which you don't want to allow the object's contents to be changed, but you *do* want to be able to change the reference to refer to different objects at different times. In other words, tail-const. (One concrete example comes from interactive graphics. Say we have some set of objects that represent pieces of geometry to be drawn. The rendering routine shouldn't modify the geometry, so the objects' contents should be const. But it should sort the geometry for the most efficient rendering order, so it needs to be able to have a non-const array of references to constant objects.) Thanks, Nathan ReedWalter Bright wrote:You can't sort an (array of)(const T). You can sort an (array of)(something of)(const T).What, exactly, is the use case that needs a solution?Before hand, let me just say that by broken, I didn't mean subvertable, but rather that using const/invariant with classes would be impractical and unmanageable. Simple example: Let's say you have a class Foo that is comparable. How do you sort an array of const(Foo)'s ? const(Foo)[] sort(const(Foo)[] arr) { ... ? The sorting algorithm doesn't matter, what matters is: how would one swap two elements in the array?
Sep 10 2007
Walter Bright wrote:Bruno Medeiros wrote:Here's another use case, which is significantly different than the other (there should be lots more to be found). Say you have a Person class, which has a name, and for whatever reasons you want the name be a String class instead of const(char)[]. Then you have: class Person { const(String) name; ... but now how do you change the name of the Person?... -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DAs Regan asked before, and how would that work for classes? This is a most fundamental issue that has not been mentioned. Without a way to declare tail const/invariant, this design, no matter how simpler or more understandable, is fundamentally *broken*.What, exactly, is the use case that needs a solution?
Sep 10 2007
Bruno Medeiros wrote:Walter Bright wrote:I'd redesign String so it holds invariant data, then just have: class Person { String name; ...What, exactly, is the use case that needs a solution?Here's another use case, which is significantly different than the other (there should be lots more to be found). Say you have a Person class, which has a name, and for whatever reasons you want the name be a String class instead of const(char)[]. Then you have: class Person { const(String) name; ... but now how do you change the name of the Person?...
Sep 10 2007
Walter Bright wrote:Bruno Medeiros wrote:Err... you do realize what this implies? This example holds not just for String but for the general case where one would want to use aggregation of immutable objects. In all those cases you'd have to redesign the aggregated class to be immutable, with all the annoyances that has. That basicly amounts to not be able to use const/invariant for classes, and then in that regard D would revert to the same status quo as Java and other languages. (Another alternative is to use an actual pointer to a class reference, but that's sure to bring another slew of inconveniences) -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DWalter Bright wrote:I'd redesign String so it holds invariant data, then just have: class Person { String name; ...What, exactly, is the use case that needs a solution?Here's another use case, which is significantly different than the other (there should be lots more to be found). Say you have a Person class, which has a name, and for whatever reasons you want the name be a String class instead of const(char)[]. Then you have: class Person { const(String) name; ... but now how do you change the name of the Person?...
Sep 11 2007
There is no way to find an optimal const solution without trying every possible const solution. (IIRC what "NP Complete" is, might be "NP really stinking hard" I'm thinking of <G>)
Sep 10 2007
Walter Bright wrote:Const, final, invariant, head const, tail const, it's grown into a monster. It tries to cover all the bases, but in doing so is simply not understandable.I was going to say that, that D's const sucks, many months ago, but didn't because I was afraid being regarded as a troll. Its not that I like const-less languages like Java (in fact, I hate them), but I think that C++'s const, with all its problems, was the right answer (for that time). It fixes the problem without putting much burden onto the programmer. D's const puts way too much burden onto the programmer, and gives very little back. Too many different combinations of const, final, invariant, pointers and references (and the fact that in D you don't immediately know if a type "T" is a reference of a value, specially while writing templates, adds to this confusion) with confusing semantics when combined (with a few special cases and lack of orthogonality). When the new const was being designed, I told in this list: "Don't try to fix what ain't broken". What I meant was: Don't try to do a new const just because you want a better const than C++s. Many people dislike C++s const, but are unable to point exactly why it is wrong. Most people doesn't even understand C++'s const, and try to get more from it than it was actually intended to provide (that is the whole point behind the new D's invariant). Sometimes people give use-cases to exemplify (STL's need for a difference between iterator<> and const_iterator<> is the first thing that comes to my mind), but then you ask what a language could provide to fix this, they don't know. This is where you should aim first you laser. When I first saw D, I was amazed with the possibilities. Now I'm somewhat scared. Perhaps one of the things that are scaring me is just like you said: there is a (at least one) monster in the language. Just my two cents... I have no interest in trolling anyone.
Sep 10 2007
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Miles wrote:Sometimes people give use-cases to exemplify (STL's need for a difference between iterator<> and const_iterator<> is the first thing that comes to my mind), but then you ask what a language could provide to fix this, they don't know. This is where you should aim first you laser.Wait, what? I presume this is a typo, but I can't for the life of me figure out what it's supposed to be. No offense :) --downs -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFG5e4tpEPJRr05fBERAvl+AKCdSR5obRn4Nr8xGeG5TFAaOtR6vACfYlCw UlAVONsjnf4ymEw8IH85wkg= =7Z1J -----END PGP SIGNATURE-----
Sep 10 2007
Downs wrote:I presume this is a typo, but I can't for the life of me figure out what it's supposed to be.Yes, it was... :-P read: This is where you should first aim your laser. I tried to make a joke... you usually kill bugs with insecticide or slippers (or a little programming), but D's const was like using a huge laser beam to exterminate a small misfeature of C++... Since you are using a laser to kill bugs (i.e. a major redesign), aim it first on those bugs that are really annoying us way back from C++.
Sep 10 2007
On Tue, 11 Sep 2007 04:50:32 +0400, Miles <_______ _______.____> wrote:Walter Bright wrote:I'm totaly agree with all you have said. -- Regards, Yauheni AkhotnikauConst, final, invariant, head const, tail const, it's grown into a monster. It tries to cover all the bases, but in doing so is simply not understandable.I was going to say that, that D's const sucks, many months ago, but didn't because I was afraid being regarded as a troll. Its not that I like const-less languages like Java (in fact, I hate them), but I think that C++'s const, with all its problems, was the right answer (for that time). It fixes the problem without putting much burden onto the programmer. D's const puts way too much burden onto the programmer, and gives very little back. Too many different combinations of const, final, invariant, pointers and references (and the fact that in D you don't immediately know if a type "T" is a reference of a value, specially while writing templates, adds to this confusion) with confusing semantics when combined (with a few special cases and lack of orthogonality). When the new const was being designed, I told in this list: "Don't try to fix what ain't broken". What I meant was: Don't try to do a new const just because you want a better const than C++s. Many people dislike C++s const, but are unable to point exactly why it is wrong. Most people doesn't even understand C++'s const, and try to get more from it than it was actually intended to provide (that is the whole point behind the new D's invariant). Sometimes people give use-cases to exemplify (STL's need for a difference between iterator<> and const_iterator<> is the first thing that comes to my mind), but then you ask what a language could provide to fix this, they don't know. This is where you should aim first you laser. When I first saw D, I was amazed with the possibilities. Now I'm somewhat scared. Perhaps one of the things that are scaring me is just like you said: there is a (at least one) monster in the language.
Sep 11 2007
Walter Bright wrote:o tail const of a struct would have to be done by making the struct a template: struct S(T) { T member; } S!(int) // tail mutable S!(const(int)) // tail constWalter, how are references handled and can you create a tail const of a reference? Which of the following are correct syntax and how is the "constness" defined: class SomeClass { some constructors some variables } const SomeClass x = new SomeClass (); SomeClass const(x) = new SomeClass (); SomeClass x = const new SomeClass (); SomeClass x = new const SomeClass (); (anything I missed out?) How can I create a tail const such that the reference is immutable but the public instance variables and public methods are mutable? What about arrays? Regards, Myron.
Sep 10 2007
Walter Bright Wrote:Const, final, invariant, head const, tail const, it's grown into a monster. It tries to cover all the bases, but in doing so is simply not understandable. Andrei and Bartosz have spent some time together going back to square one with what are we trying to achieve with const, and came up with another proposal. What we are trying to achieve: a) utility for functional programming b) better modularity by self-documenting interfaces better c) be able to treat reference types as if they were value types (i.e. strings should behave to the user like value types, even though they are references) The insights they came up with were: 1) final (i.e. 'head const') is not necessary for a, b or c. final is a local thing, and not strictly necessary. 2) tail const can be handled in other ways, read on So, what we are left with is: o no more final o const and invariant now mean "fully const" and "fully invariant", where fully means "head and tail combined": const int x = 0; // x is constant const int* p = &x; // neither p nor *p can be changed const(int*) p = &x; // neither p nor *p can be changed const(int)* p = &x; // p can change, *p cannot be changed o const and invariant are transitive. There is no way to specify a (pointer to)(const pointer to)(mutable int). o tail invariant for an array or pointer type can be done using the existing syntax: invariant(char)[] s; // string, i.e. an array of invariant chars const(T)* p; // pointer to tail const T o tail const of a struct would have to be done by making the struct a template: struct S(T) { T member; } S!(int) // tail mutable S!(const(int)) // tail const o one can construct a template to generically produce tail const or tail invariant versions of a type. o it will be illegal to attempt to change the key value of a foreach loop, but the compiler will not be able to diagnose all attempts to do so o static const/invariant means the initializer is evaluated at compile time. non-static const/invariant means it is evaluated at run time. o no initializer means it is assigned in the corresponding constructor. o const/invariant declarations will always allocate memory (so their addresses can be taken) o So, we still need a method to declare a constant that will not consume memory. We'll co-opt the future macro syntax for that: macro x = 3; macro s = "hello";Time for a rethink. I think I may have (part of) a solution. Fundermentally its a property of an individual pointer or reference type. const means - I will not change what I point to. invariant means - no-one will change what I point to. Fundermentally this can be applied independently to every pointer in a chain of pointers to pointers to pointers... The challenge for the language designer is to make this easily expressible and understandable to the user. We are still thinking along C++ lines. Maybe constraints are (part of) the answer. One powerful concept introduced was that const and invariant could be transitive. This helps in some specific cases and in might be an idea to make transitivity declarable. i.e. transitive const versus vanilla const. Similarly you can use brackets of some kind to specify the scope (i.e. which range of pointers in a change) that constness or invariantivity applies to. However, I think doing it the c++ way is not the only answer. constness only comes into play in interfaces. Interfaces have contracts. Lets use these to specify the constraint clearly and concisely. i.e. instead of: const int* foo(const double* bar, invariant int* quango); how about: pre { assert(bar.const == true); assert(quango.invariant == true); } post { // how do you say return value? assert(returnValue.const == true); } int* foo(double* bar, int* quango) { } For a trivial function like that it doesn't help readability that much. But for something more complicated it will. instead of: invariant int x; invariant int* y; const* invariant int* z; //syntax fuzzy here invariant int x; int* y; int** z; assert(z.const == true); assert((*z).invariant == true); Just more syntactic sugar. Likewise int x; const int* y; const* const int* z; could become: int x; const int* y; transitive const int** z; //insert favourite keyword for 'transistive' here Just some incomplete thoughts to throw into the mix. Regards, Bruce.
Sep 11 2007
Walter Bright wrote:Const, final, invariant, head const, tail const, it's grown into a monster. It tries to cover all the bases, but in doing so is simply not understandable.Does that mean I'm a genius, or insane? :P[snip] o no more finalNot 100% sure what you mean by "no more". But then, "final" was always kind of like the appendix of the new const system; I always viewed it as something of a side issue since it didn't affect the type of declarations.o const and invariant now mean "fully const" and "fully invariant", where fully means "head and tail combined": const int x = 0; // x is constant const int* p = &x; // neither p nor *p can be changed const(int*) p = &x; // neither p nor *p can be changed const(int)* p = &x; // p can change, *p cannot be changedOk.o const and invariant are transitive. There is no way to specify a (pointer to)(const pointer to)(mutable int). o tail invariant for an array or pointer type can be done using the existing syntax: invariant(char)[] s; // string, i.e. an array of invariant chars const(T)* p; // pointer to tail const TThis makes me happy, because although I understood the what, I never could grasp the why of "invariant(char)[]" meaning that you couldn't change the elements of the array.o tail const of a struct would have to be done by making the struct a template: struct S(T) { T member; } S!(int) // tail mutable S!(const(int)) // tail constThis is... not so good. I'll come back to this...o one can construct a template to generically produce tail const or tail invariant versions of a type.This makes me rather nervous; it seems like a bad thing that we can no longer do tail-const, and have to resort to wrapping templates to do it. I mean, in the end, you can make a const version of any type by replacing all fields with read-only properties; but then you can't cleanly cast between them.o it will be illegal to attempt to change the key value of a foreach loop, but the compiler will not be able to diagnose all attempts to do soI assume this means that for built-in types, instead of being ( ref key, ref value ; aggregate ) We'll have ( const ref key, ref value ; aggregate ) If so; I'll be happy about that. So long as I can do evil cr*p like: ( ref idx, ref chr ; string.foo ) ++idx; Why, you ask? Er, you don't wanna know... :Po static const/invariant means the initializer is evaluated at compile time. non-static const/invariant means it is evaluated at run time.Ok.o no initializer means it is assigned in the corresponding constructor.Sounds good.o const/invariant declarations will always allocate memory (so their addresses can be taken)I guess this is good from a consistency standpoint.o So, we still need a method to declare a constant that will not consume memory. We'll co-opt the future macro syntax for that: macro x = 3; macro s = "hello";The syntax doesn't *really* speak to me; honestly, I was expecting you to use "alias" before I scrolled down and saw "macro". Thing is, if this works for arbitrary expressions, does that mean this will be possible: macro string = char[]; My main problem with this is the loss of tail const on structs/classes. Others have already listed several useful things that you won't be able to do because of this, so I won't bother with that. This problem seems to be unique to structs and classes. This is because every other reference type is written in such a way that you can "split" the type in such a way as to get tail-const semantics. For example: const(char[]) versus const(char)[]. This can't be done with structs or classes since their types are single identifiers. So what we need is some way to write that split. Really, what we're saying is "I don't want *this* to be const, but I do want what it references to be const". Back when I was writing my article on the upcoming const changes, I gave each kind of const a different, longer name to help differentiate them; the names I gave const and invariant were "reference const" and "reference immutable". So, stealing a little bit of C++ syntax, what about "const& T" being a tail-const version of some struct or class T? Since this could potentially introduce synonyms in other places, I would also propose the following: const& int a; // Error: cannot use reference const on an atomic type const& int* b; // Error: equivalent to const(int)* struct V { int a; } const& V c; // Warning: V does not have any references struct R { int* a; } const& R d; // OK class C {} const& C e; // OK Yes, this means there is a distinction between structs, classes and "everything else". But honestly, I don't think we can have tail const without this distinction. Maybe disallowing const& on arrays and pointers isn't a good idea; but I do think we need some kind of tail-const for structs and classes. Thoughts? -- Daniel
Sep 11 2007
Daniel Keep wrote: > This problem seems to be unique to structs and classes. This is becauseevery other reference type is written in such a way that you can "split" the type in such a way as to get tail-const semantics. For example: const(char[]) versus const(char)[]. This can't be done with structs or classes since their types are single identifiers.I came to the same conclusion, the basic problem is the inability to put a * or [] outside the () of const.So what we need is some way to write that split. Really, what we're saying is "I don't want *this* to be const, but I do want what it references to be const".Exactly.So, stealing a little bit of C++ syntax, what about "const& T" being a tail-const version of some struct or class T? Since this could potentially introduce synonyms in other places, I would also propose the following: const& int a; // Error: cannot use reference const on an atomic type const& int* b; // Error: equivalent to const(int)* struct V { int a; } const& V c; // Warning: V does not have any references struct R { int* a; } const& R d; // OK class C {} const& C e; // OK Yes, this means there is a distinction between structs, classes and "everything else". But honestly, I don't think we can have tail const without this distinction. Maybe disallowing const& on arrays and pointers isn't a good idea; but I do think we need some kind of tail-const for structs and classes. Thoughts?In D when we write: Foo f; we are declaring a reference to a Foo. The problem, as you mentioned is the inability to seperate the reference from the Foo for purposes of declaring const, so... I was initially thinking that for classes we might write: class Foo { int a; } const(Foo)& pFoo; //pFoo can change, pFoo.a cannot Where the & doesn't introduce another reference or level of indirection, in fact it does _nothing_ at all except allowing us to place it outside the () of const. Meaning, that these two declarations would in fact be identical: Foo& pFoo; Foo pFoo; which will no doubt bother some people, perhaps a lot of people? The first form could be made illegal, after all it's pointless(right?) to take a reference to a reference. Alternately, and I think I might prefer this solution, perhaps _adding_ something to the const() is the solution. eg. class Foo { int a; } const(*Foo) pFoo; //pFoo can change, pFoo.a cannot As in, were saying "the value of Foo is const", therefore implying the reference is not. As for structs, as someone else has mentioned there isn't really any difference between making a struct variable const and making all members of that struct const, without a pointer or reference they are the same thing. So, saying: struct Bar { int a; Foo pFoo; } const(Bar) bar; Is perfectly sufficient in that case. The difference occurs when you want to make _some_ of the members consts and not the others, typically you want to make references/pointers const, or tail const. The syntax: struct Bar { int a; Foo pFoo; } const(Bar)& bar; doesn't make the same sense for structs because there is no reference involved (as many programmers would expect upon reading that). Neither does the * syntax I proposed above: struct Bar { int a; Foo pFoo; } const(*Bar) bar; because that would logically make all members of the struct const, and we get that already. Assuming there is even a requirement to make select members of a struct (initially declared without const) const (if there isn't we have no problem) then using a template seems the most sensible solution. It would also allow you to apply const or tail const where appropriate. eg. From this initial struct: struct Bar { int a; //we want this to be const Foo pFoo; //we want this to be tail const } Our template generates this: struct BarConst { const int a; const(*Foo) pFoo; } Regan
Sep 11 2007
Regan Heath wrote:Assuming there is even a requirement to make select members of a struct (initially declared without const) const (if there isn't we have no problem) then using a template seems the most sensible solution. It would also allow you to apply const or tail const where appropriate. eg.Talking to myself, a sure sign of mental instability ;) The same applies to making select members of a class const. I think it's important to remember that we're talking about _modifying_ an existing class/struct definition _adding_ const where it was not initially. This would only be required in cases where: 1. you need different const rules for instances of the same class/struct in the same version of the code. 2. you need to const correct a 3rd party API. In any other case you can simply apply const to the class/struct definition directly, no need for a template to do it. eg. struct Something { const(*Foo) pFoo; const int a; int b; } There will be no need to _modify_ this with a template because it will always need to have a mutable reference to a const Foo and that requirement won't be different for some instances and not others. It may change in future versions of the code, but in that case a simple change to the struct definition is all you need, not a template. I think the ability to tail const a class reference with something like: class Foo { int a; } const(*Foo) pFoo; Handles 99% of the cases which we should realistically be worried about. Regan
Sep 11 2007
On Mon, 10 Sep 2007 23:15:09 +0400, Walter Bright <newshound1 digitalmars.com> wrote:o const and invariant are transitive. There is no way to specify a (pointer to)(const pointer to)(mutable int).What's wrong with such pointers and why they are disabled by language? -- Regards, Yauheni Akhotnikau
Sep 11 2007
Overall, I like this solution MUCH better than before. I have some points to make, but let me say thanks for working on this and taking everyone's opinion into account. "Walter Bright" wroteConst, final, invariant, head const, tail const, it's grown into a monster. It tries to cover all the bases, but in doing so is simply not understandable.Hear hear.o const and invariant now mean "fully const" and "fully invariant", where fully means "head and tail combined": const int x = 0; // x is constant const int* p = &x; // neither p nor *p can be changed const(int*) p = &x; // neither p nor *p can be changed const(int)* p = &x; // p can change, *p cannot be changedWhat about const(int) x = 0? I'm guessing the same as const int x = 0? Is it safe to say that const(T) x is equivalent to const T x? What about classes?o tail const of a struct would have to be done by making the struct a template: struct S(T) { T member; } S!(int) // tail mutable S!(const(int)) // tail constI didn't see it brought up by anyone else, so I'll ask. Did you mean: struct S(T) { T * member; } ??? Because I always thought tail const had to do with pointers. If not, can someone please explain the difference between the two structs in Walter's example?o one can construct a template to generically produce tail const or tail invariant versions of a type.This prevents casting, which from what I can interpret from the previous 2.0 proposal (the monster), you could do. i.e. struct MyNiftyPointer(T) {T * ptr; int someOtherCoolValue;} void myGreatFunction(MyNiftyPointer!(const(int)) x) { // do something that doesn't modify *x.ptr } void test() { MyNiftyPointer!(int) p; // set up p ... myGreatFunction(p); // will this compile? } Not that I really care much. You may be able to implement an opImplicitCast that worked around this problem. Really, I only see this feature being useful for a smart-pointer/array type, so I'm pretty sure I'll never use it.o So, we still need a method to declare a constant that will not consume memory. We'll co-opt the future macro syntax for that: macro x = 3; macro s = "hello";First, I don't like the syntax. I understand it's roots, as #define is now being replaced by macro, but #define seems a more descriptive keyword than macro when trying to define something as being something else. I agree with Daniel Keep when he said he expected alias. Second, I'm trying to understand what the real purpose of this is. Could someone define the different types of memory and why we need different declarations to put things in those different types? For example, "doesn't consume memory" doesn't make sense to me. The bytes gotta go somewhere! Third, how would you define constants that are not implicitly typed, like a structure? I can see this being useful for something like a configuration table, or a table of CRC values. -Steve
Sep 11 2007
Steven Schveighoffer wrote:Second, I'm trying to understand what the real purpose of this is. Could someone define the different types of memory and why we need different declarations to put things in those different types? For example, "doesn't consume memory" doesn't make sense to me. The bytes gotta go somewhere!For numeric constants which are known at compile time, there's not necessarily a location in the executable's data-sections where they are stored; they may just be incorporated as immediate values into the machine instructions, and/or folded into other expressions at compile time. (For string constants known at compile time they are still going to have to be stored in the executable image.) However, if you ever take the address of such a constant it needs to actually be stored. For a regular declaration of a const variable, the compiler can optimize away the stored version if it can determine that the address is never taken, but this often isn't possible (think of class member variables - the compiler can't guarantee that no client code will ever take the address). On the other hand it would be illegal to take the address of a macro. Thanks, Nathan Reed
Sep 11 2007
On 9/11/07, Nathan Reed <nathaniel.reed gmail.com> wrote:For a regular declaration of a const variable, the compiler can optimize away the stored version if it can determine that the address is never taken, but this often isn't possible (think of class member variables - the compiler can't guarantee that no client code will ever take the address).Then just decree that it be illegal to take the address of a const class member variable. Problem solved. What's wrong with: class C { const int X = 42; /* not stored; address may not be taken */ static int Y = 42; /* consumes memory; address may be taken */ } I dislike your macro idea, because I want my consts to have a type. I /like/ type safety, and I want to keep it. I want my constants to be of the type I declare them to be, not just a piece of text.
Sep 11 2007
Janice Caron wrote:I dislike your macro idea, because I want my consts to have a type. I /like/ type safety, and I want to keep it. I want my constants to be of the type I declare them to be, not just a piece of text.Hmmmm... if I got that right, macros will definitely *not* be "pieces of text", but abstract syntax trees. So, if you'd do "macro x=5;" (or whatever the macro syntax will be), and you try `char[] s="abc"~x;` you'll get a nice, clean type error. As you liek it! :) regards, Frank
Sep 11 2007
Hmmmm... if I got that right, macros will definitely *not* be "pieces of text", but abstract syntax trees.Macros have their place. I'm not knocking them. But they're not the right mechanism for declaring constants. On the other hand, const Type name = value; is. (replace const with static if necessary - see earlier in thread). Of course, it really should be invariant Type name = value; with the current keywords, though if we switch from invariant/const to const/readonly that mistake will likely disappear.So, if you'd do "macro x=5;" (or whatever the macro syntax will be), and you try `char[] s="abc"~x;` you'll get a nice, clean type error.Looks the same as C to me. #define x 5 strcat(s,"abc"); strcat(s,x); /* compile error */ That doesn't count as strong typing.
Sep 11 2007
Janice Caron wrote:You're jumping to conclusions here. I doubt _very_ much that Walter plans to implement macro like #define in C. Especially after all the trouble he went through to remove the preprocessor completely. ReganHmmmm... if I got that right, macros will definitely *not* be "pieces of text", but abstract syntax trees.Macros have their place. I'm not knocking them. But they're not the right mechanism for declaring constants. On the other hand, const Type name = value; is. (replace const with static if necessary - see earlier in thread). Of course, it really should be invariant Type name = value; with the current keywords, though if we switch from invariant/const to const/readonly that mistake will likely disappear.So, if you'd do "macro x=5;" (or whatever the macro syntax will be), and you try `char[] s="abc"~x;` you'll get a nice, clean type error.Looks the same as C to me. #define x 5 strcat(s,"abc"); strcat(s,x); /* compile error */ That doesn't count as strong typing.
Sep 11 2007
Janice Caron wrote:Isn't!!!111!!So, if you'd do "macro x=5;" (or whatever the macro syntax will be), and you try `char[] s="abc"~x;` you'll get a nice, clean type error.Looks the same as C to me.#define x 5 strcat(s,"abc"); strcat(s,x); /* compile error */ That doesn't count as strong typing.It is! You'll be able to do "typeof(x)" and probably get "int"... :-) Regards, Frank
Sep 11 2007
Janice Caron wrote:On 9/11/07, Nathan Reed <nathaniel.reed gmail.com> wrote:That places totally unnecessary restrictions on the programmer...there's absolutely no reason why you shouldn't be able to take the address of something const.For a regular declaration of a const variable, the compiler can optimize away the stored version if it can determine that the address is never taken, but this often isn't possible (think of class member variables - the compiler can't guarantee that no client code will ever take the address).Then just decree that it be illegal to take the address of a const class member variable. Problem solved.I dislike your macro idea, because I want my consts to have a type. I /like/ type safety, and I want to keep it. I want my constants to be of the type I declare them to be, not just a piece of text.It's not /my/ macro idea. :) (For the record, I don't really like the idea of using the macro keyword for this, either.) Although, as other people have pointed out, this doesn't break type safety, just makes the type not explicitly stated in the code. Thanks, Nathan Reed
Sep 11 2007
Nathan Reed wrote:Janice Caron wrote:In that way it's a bit like 'auto' ReganOn 9/11/07, Nathan Reed <nathaniel.reed gmail.com> wrote:That places totally unnecessary restrictions on the programmer...there's absolutely no reason why you shouldn't be able to take the address of something const.For a regular declaration of a const variable, the compiler can optimize away the stored version if it can determine that the address is never taken, but this often isn't possible (think of class member variables - the compiler can't guarantee that no client code will ever take the address).Then just decree that it be illegal to take the address of a const class member variable. Problem solved.I dislike your macro idea, because I want my consts to have a type. I /like/ type safety, and I want to keep it. I want my constants to be of the type I declare them to be, not just a piece of text.It's not /my/ macro idea. :) (For the record, I don't really like the idea of using the macro keyword for this, either.) Although, as other people have pointed out, this doesn't break type safety, just makes the type not explicitly stated in the code.
Sep 11 2007
On 9/11/07, Nathan Reed <nathaniel.reed gmail.com> wrote:Remember, this is a special circumstance - /as a class member variable/ Consider: class C { const int n = 42; /* other stuff */ } Suppose you new a thousand of those things. What's the point of making a thousand ints, all the same. Why not just do: class C { static const int n = 42; /* other stuff */ } and only consume four bytes. I argue that per-class-instance const variables is so silly, that you might just as well let the compiler "disappear" them.Then just decree that it be illegal to take the address of a const class member variable. Problem solved.That places totally unnecessary restrictions on the programmer...there's absolutely no reason why you shouldn't be able to take the address of something const.It's not /my/ macro idea. :)My apologies. I lost track of to whom I was replying.Although, as other people have pointed out, this doesn't break type safety, just makes the type not explicitly stated in the code.And this is different to #define how exactly?
Sep 11 2007
Janice Caron wrote:class C { const int n = 42; /* other stuff */ } Suppose you new a thousand of those things. What's the point of making a thousand ints, all the same. Why not just do: class C { static const int n = 42; /* other stuff */ } and only consume four bytes. I argue that per-class-instance const variables is so silly, that you might just as well let the compiler "disappear" them.Fine for things that are known at compile time. But it's also possible to have const variables whose values are not known till runtime. For instance void foo (int bar) { const int baz = bar * 47; ... } or class instance variables: class Foo { const int bar; this (int baz) { this.bar = baz; } } The variable needs to be initialized but is then not supposed to change over its lifetime.#define does text substitution. In C, you could write something like this: #define THREE 3 float pi = THREE.14159; With D macros that would not be allowed. Thanks, Nathan ReedAlthough, as other people have pointed out, this doesn't break type safety, just makes the type not explicitly stated in the code.And this is different to #define how exactly?
Sep 11 2007
On 9/11/07, Nathan Reed <nathaniel.reed gmail.com> wrote:void foo (int bar) { const int baz = bar * 47; ... }That's not a class member variable. That's a local variable. It's a different animal. In the case of local variables, the compiler can decide whether or not memory storage is required.class Foo { const int bar; this (int baz) { this.bar = baz; } } The variable needs to be initialized but is then not supposed to change over its lifetime.That can be done in different ways. Walter was originally going to allow final for that purpose, but final is now dropped. I think that the above example will not compile under Walter's new plans, because const is unmodifiable even in a constructor. Of course, I could be wrong. One way to rewrite that, though, would be class Foo { private int bar_; this (int baz) { bar_ = baz; } int bar() return bar_; }#define does text substitution. In C, you could write something like this: #define THREE 3 float pi = THREE.14159; With D macros that would not be allowed.True. But I want more than that. I want to be able to distinguish between const int x = 42; const uint x = 42; etc. And if I want type deduction, of course the following would work just fine: const x = 42;
Sep 11 2007
Janice Caron wrote:On 9/11/07, Nathan Reed <nathaniel.reed gmail.com> wrote:No problem: macro x = 42; //int macro x = 42U; //uint macro x = 42L; //long macro x = 42UL; //ulong In addition: macro x = 2_147_483_648; //long See: "Decimal Literal" http://www.digitalmars.com/d/lex.html Regan#define does text substitution. In C, you could write something like this: #define THREE 3 float pi = THREE.14159; With D macros that would not be allowed.True. But I want more than that. I want to be able to distinguish between const int x = 42; const uint x = 42;
Sep 11 2007
On 9/11/07, Regan Heath <regan netmail.co.nz> wrote:No problem: macro x = 42; //int macro x = 42U; //uint macro x = 42L; //long macro x = 42UL; //ulongMaybe it's just a gut feeling thing. const ulong x = 42; /* obvious to newbies what it does */ macro x = 42UL; /* looks weird */
Sep 11 2007
On 9/11/07, Janice Caron <caron800 googlemail.com> wrote:I argue that per-class-instance const variables is so silly, that you might just as well let the compiler "disappear" them.Otherwise I'll end up doing class C { enum : int { n = 42; } } because I want my type specified at the point of declaration.
Sep 11 2007
On 9/11/07, Janice Caron <caron800 googlemail.com> wrote:What's wrong with: class C { const int X = 42; /* not stored; address may not be taken */ static int Y = 42; /* consumes memory; address may be taken */ }Of course, I actually meant: class C { const int X = 42; /* not stored; address may not be taken */ static const int Y = 42; /* consumes memory; address may be taken */ } The point being that for constant data to consume memory *per-class-instance* is silly.
Sep 11 2007
This is a mess! The examples given do not indicate how references will be taken care of nor do they indicate how to deal with templated functions/methods that change behaviour based on type. In this method, I want to make toValue final (like Java) if it is a reference, and const if it is a primitive/structure, how do I do that? void doSomthing(T) (*declare final* T toValue) { *whole bunch of common code* static if (is(T : someobject)) { work with someobject } static if (is(T == int)) { work with int } static if (is(T == char[])) { work with char[] } ... *whole bunch of other common code* } In D, there are five main type classes: 1. Primitives (including pointers) 2. Structs - value type 3. Classes - reference semantics 4. Arrays - reference semantics 5. Delegates/Function pointers Until constness can deal with all types simply (and elegantly), then it should not be introduced. This way leads to C++ and the kitchen sink approach. Java does well because it is not a kitchen sink. Please demote D2.0 from the front-page and revert back to D1.0 so that new people are not confused with experimental versions. Regards, Myron.
Sep 11 2007
On 9/10/07, Walter Bright <newshound1 digitalmars.com> wrote:o const/invariant declarations will always allocate memory (so their addresses can be taken)I'd hadn't really thought about this before. But now I have. I want to be able to *express the idea* that the value I am declaring shall never change. To my mind: const int NUM_DAYS_IN_WEEK = 7; successfully expresses that idea, and frankly, I whether or not NUM_DAYS_IN_WEEK consumes memory should not be my call. That is an implementation detail, and should be the compiler's problem, not mine.o So, we still need a method to declare a constant that will not consume memory. We'll co-opt the future macro syntax for that:Isn't that a bit like "register" or "inline"? Those keywords went the way of the dodo because it was decreed that the compiler could do a better job at figuring out what to inline or put in registers than the programmer ever could. Isn't this the same? Surely, the compiler can make the decision as to whether or not the value gets stored in memory. Why should I have to? If the program does not take the address, and if sizeof the variable is sufficiently small, then don't store in memory, otherwise do. If it's a library and you don't know what the calling code will do, let the compiler take its best guess. If it guesses wrongly, then either a few bytes of memory will have been consumed, or some jiggery pokery will be required at the call site. But either way, don't make the programmer choose.macro x = 3; macro s = "hello";And bang goes type safety, right there!
Sep 11 2007
Janice Caron wrote:I want to be able to *express the idea* that the value I am declaring shall never change. To my mind: const int NUM_DAYS_IN_WEEK = 7; successfully expresses that idea, and frankly, I whether or not NUM_DAYS_IN_WEEK consumes memory should not be my call. That is an implementation detail, and should be the compiler's problem, not mine.Agree. Thanks, Nathan Reed
Sep 11 2007
Walter Bright Wrote:Const, final, invariant, head const, tail const, it's grown into a monster. It tries to cover all the bases, but in doing so is simply not understandable. <snip>This seems to have generated a lot of discussion... I just want to weigh in with a strong vote of approval for Walter, Andrei and Bartosz's proposal. I like it. It works and the syntax is straightforward. Admittedlly there may be cases where a different syntax/keyword/implementation would work better for that case, but overall I think they've achieved good coverage with minimal structure. Paul
Sep 11 2007
Sean Kelly Wrote:Bruce Adams wrote:[ouch - my grammar and speiling was terrible this morning.]Sean Kelly Wrote:htod works for simple cased. More complex cases require GregorR's BCD or simply a manual effort.Walter Bright wrote:I seek enlightenmnet for at least two problems with that explanation. windows.h is a C binding not a D binding. I'm not clear how one translates to the other yet as I've avoided bi-lingual stuff so far. Presumably the D binding is created using htod.Bruce Adams wrote:That sounds about right. When we converted const values to enum values in the Tango Win32 headers, app size dropped by roughly 46k. But there were issues with some of those enum values having the wrong type (-1 set to int instead of uint), which led to a few strange bugs. Seanwindows.h in all its terrifying glory has 10,000 macro declarations. If each one occupied 4 bytes of static data, there's 40K of bloat in every exe.I'm not clear why this is even needed. Surely "static const" implies some level of don't consume any memory by virtue of meaning "available at compile time". If you need more than that, rather than trusting the compiler then I second "inline" rather than macro, but honestly I can't think of an example where this will give you a worthwhile performance gain (unlike an inline function).o So, we still need a method to declare a constant that will not consume memory. We'll co-opt the future macro syntax for that: macro x = 3; macro s = "hello";I thought D followed the you only pay for what you use philosophy. So if I import my windows.d module I will only pay the cost of the variables I actually use. My friendly neighbourhoold compiler, being clever, mightl also make an effort to minimise the cost of those too.D currently links at the file level, so if you use anything in a file you get the whole thing. Some linkers are able to link at the section level (a piece of a file), but D does not support this yet (see comments regarding gc-sections using ld, I believe--there's an issue in BugTracker about this).While we're on the subject of windows. 40K means nothing. In an embedded system yes. Windows is bloated to the point where 40K in a user application means de nada. (I shudder at the 4Gb games that follow in its wake too). I have know idea where the windows mobile / CE / pocket PC api falls here.It matters to some people, particularly those coming from C and comparing EXE sizes. It may not be relevant as far as general development on Windows is concerned, but it's something library developers must take into consideration. SeanI strongly disapprove of designing language features based around a particular current compiler implementation, especially one that is currently less than optimal by the sound of it. Can anyone come up with an example where this would actually provide a significant benefit?
Sep 11 2007
Nathan Reed Wrote:Janice Caron wrote:Already agreed on another thread but worth every extra vote.I want to be able to *express the idea* that the value I am declaring shall never change. To my mind: const int NUM_DAYS_IN_WEEK = 7; successfully expresses that idea, and frankly, I whether or not NUM_DAYS_IN_WEEK consumes memory should not be my call. That is an implementation detail, and should be the compiler's problem, not mine.Agree. Thanks, Nathan Reed
Sep 11 2007
Agreed! Bruce Adams Wrote:Nathan Reed Wrote:Janice Caron wrote:Already agreed on another thread but worth every extra vote.I want to be able to *express the idea* that the value I am declaring shall never change. To my mind: const int NUM_DAYS_IN_WEEK = 7; successfully expresses that idea, and frankly, I whether or not NUM_DAYS_IN_WEEK consumes memory should not be my call. That is an implementation detail, and should be the compiler's problem, not mine.Agree. Thanks, Nathan Reed
Sep 11 2007
Walter Bright wrote:Const, final, invariant, head const, tail const, it's grown into a monster. It tries to cover all the bases, but in doing so is simply not understandable.I have not really been following the discussions thus far, but would still like to offer my uninformed view on things. (More questions than opinions actually) 1. I think one reason it is not understandable is the poor choice of keywords. My latest reiteration on the keywords (elsewhere in this thread): http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=58135 (This may sound like a silly issue, but the advantages to using descriptive names should not be underestimated. Imagine using banana/apple/orange instead of int/float/void.) 2. There are two distinct problems. Access control vs constantness of data. The old proposal doesn't really take advantage of that distinction. 3. For write access control, I don't see transitivity making as much sense. There are cases where you want write access to a certain depth. Certain members of a class need not be part of that class, and therefore not bound by the same non-mutability requirements. Robert Fraser has posted a few use cases too. What are the motivations for transitivity here? What problems does it solve? Are there alternative solutions to those problems? 4. Transitivity could still make sense for constant data (there are few cases were it makes sense to have for example a compile time rommable pointer pointing to mutable data). An alternative suggestion would be to make a better separation between constness and access control by making const intransitive and only referring to access control, i.e const would prevent modification access to data in the following forms. - writing though a pointer - modifying class fields - calling non-readonly methods on classes - changing element of an array - appending to an array This means, more or less the D 2.000 const but without transitivity, coupled with the recently suggested invariant proposal. Combine this with my wish to rename invariant->const, const->readonly: * readonly handle to access control * const refers to constness of the actual data * readonly would be intransitive * const would remain transitive data -- const -- transitive access -- readonly -- intransitive simple, right? :) The behavior of readonly would become (all of this should be deducible, so just skip this part): A readonly type prevents modifying access through that type. readonly int * a; // no writing allowed through a readonly int b; // readonly doesn't apply to non-reference types readonly Class c; // c can be reassigned but is a readonly reference readonly Struct d; // members are readonly, d isn't readonly int[] e; // e may change, e[] may not Structs are value types, so readonly doesn't apply to them. It does however apply it its members. struct S { int[] arr; String str; } readonly S s; Here, s.arr and s.str are readonly. This means that as far as readonly is concerned, a struct containing a reference to data behaves the same as a free reference to data. For arrays: readonly Class[] g; // readonly array of mutable classes readonly(Class)[] h; // mutable array of readonly classes readonly readonly(Class)[] i; // readonly array of readonly classes TransitiveReadonly!() is possible to implement. references to constant data are automatically readonly. const(int)[] j; // j is readonly Intransitivity allows all combinations of mutability [m] and immutability [i] for nested types: [m][m][m] int[][][] [i][m][m] readonly int[][][] [m][i][m] readonly(int[][])[] [m][m][i] readonly(int[])[][] [i][i][m] readonly(readonly(int[][]))[] [m][i][i] readonly(readonly(int[])[])[] [i][m][i] readonly readonly(int[])[][] [i][i][i] readonly(readonly(readonly(int[]))[])[] As far as I can see this resolves the issues with head/tail const and the issues with class references in the latest proposal. But I have probably missed many issues. -- Oskar
Sep 11 2007
Ok, seems my Oskar "agreing spree" has ended. :P Oskar Linde wrote:TransitiveReadonly!() is possible to implement.Are you sure? How would that work in general terms, for say, a class? -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Sep 12 2007
Walter Bright Wrote:1) final (i.e. 'head const') is not necessary for a, b or c. final is a local thing, and not strictly necessary. 2) tail const can be handled in other ways, read on So, what we are left with is: o no more final o const and invariant now mean "fully const" and "fully invariant", where fully means "head and tail combined":If head const is not necessary, why not having const and invariant meaning 'tail const' and 'tail invariant' ? This way no need to design templates.
Sep 12 2007
Yes. Const does suck. Walter Bright wrote:Const, final, invariant, head const, tail const, it's grown into a monster. It tries to cover all the bases, but in doing so is simply not understandable. Andrei and Bartosz have spent some time together going back to square one with what are we trying to achieve with const, and came up with another proposal. What we are trying to achieve: a) utility for functional programming b) better modularity by self-documenting interfaces better c) be able to treat reference types as if they were value types (i.e. strings should behave to the user like value types, even though they are references) The insights they came up with were: 1) final (i.e. 'head const') is not necessary for a, b or c. final is a local thing, and not strictly necessary. 2) tail const can be handled in other ways, read on So, what we are left with is: o no more final o const and invariant now mean "fully const" and "fully invariant", where fully means "head and tail combined": const int x = 0; // x is constant const int* p = &x; // neither p nor *p can be changed const(int*) p = &x; // neither p nor *p can be changed const(int)* p = &x; // p can change, *p cannot be changed o const and invariant are transitive. There is no way to specify a (pointer to)(const pointer to)(mutable int). o tail invariant for an array or pointer type can be done using the existing syntax: invariant(char)[] s; // string, i.e. an array of invariant chars const(T)* p; // pointer to tail const T o tail const of a struct would have to be done by making the struct a template: struct S(T) { T member; } S!(int) // tail mutable S!(const(int)) // tail const o one can construct a template to generically produce tail const or tail invariant versions of a type. o it will be illegal to attempt to change the key value of a foreach loop, but the compiler will not be able to diagnose all attempts to do so o static const/invariant means the initializer is evaluated at compile time. non-static const/invariant means it is evaluated at run time. o no initializer means it is assigned in the corresponding constructor. o const/invariant declarations will always allocate memory (so their addresses can be taken) o So, we still need a method to declare a constant that will not consume memory. We'll co-opt the future macro syntax for that: macro x = 3; macro s = "hello";
Sep 12 2007