digitalmars.D - const again
- Walter Bright (44/44) Dec 06 2007 As a result of all the const comments here, and some serious semantic
- Janice Caron (22/34) Dec 06 2007 May I be the first to say I am very happy with everything you've said.
- Walter Bright (15/36) Dec 06 2007 There are a couple problems with it, the worst of which is its impact on...
- Janice Caron (22/38) Dec 06 2007 Good point. You'd need it for a class, but not for a struct. I hadn't
- Walter Bright (11/56) Dec 06 2007 I think it would be, especially from the point of view of generic
- Janice Caron (8/12) Dec 06 2007 Got it.
- Steven Schveighoffer (42/76) Dec 06 2007 What happens if you have this?
- Walter Bright (7/26) Dec 06 2007 It is perfectly consistent. I don't see why it is bad.
- Steven Schveighoffer (28/54) Dec 06 2007 const(T)*[] x;
- Walter Bright (12/46) Dec 06 2007 There's the problem we're having. While a class reference is implemented...
- Steven Schveighoffer (39/83) Dec 07 2007 I guess it isn't :) I thought:
- Sean Kelly (20/54) Dec 06 2007 One thing that concerns me. If we assume that "enum x = 3" is simply
- Walter Bright (7/37) Dec 06 2007 It would be implicitly typed to the type of its initializer, or you can
- Christopher Wright (16/36) Dec 06 2007 So if I have:
- Walter Bright (6/27) Dec 06 2007 No, it is a mutable pointer to a const Foo. A const pointer to a const
- Christopher Wright (3/20) Dec 06 2007 So why do arrays take their const status from their elements when
- Walter Bright (4/25) Dec 06 2007 ??? I think there's a misunderstanding here on what arrays are. Arrays
- Christopher Wright (2/28) Dec 07 2007 But I can reassign a const Foo, right?
- Sean Kelly (15/55) Dec 06 2007 I can't say I'm terribly fond of using "enum" for this, but it is
- Walter Bright (16/29) Dec 06 2007 Yes for that reason, and the other reason is one rarely wants storage
- Sean Kelly (4/34) Dec 06 2007 Oops, one last thing. Does the transitivity mean it would be impossible...
- Walter Bright (2/4) Dec 06 2007 Yes.
- Ary Borenszweig (4/9) Dec 06 2007 Why not
- Sean Kelly (4/14) Dec 06 2007 Assuming that we need a new keyword, I like "macro" better. We're going...
- Ary Borenszweig (3/17) Dec 06 2007 That's the idea. ;-)
- Derek Parnell (13/18) Dec 06 2007 I agree. And I would still like to be able to group such definition
- Walter Bright (4/8) Dec 06 2007 It's been suggested several times. It doesn't make much aesthetic sense
- Derek Parnell (25/35) Dec 06 2007 I definitely think that overloading 'enum' to declare definitions is qui...
- Ary Borenszweig (10/20) Dec 06 2007 Well, macros like that would almost always refer to primitive types:
- Sean Kelly (3/13) Dec 06 2007 So are you saying that it would be fine without the type qualifier, or
- Walter Bright (3/17) Dec 06 2007 Since the optional type qualifier should be supported, it doesn't make
- Sean Kelly (9/27) Dec 07 2007 It may be stretching the desire to use "macro" too far, but casting
- Walter Bright (13/23) Dec 08 2007 Yes, it could be. But I just can't see it being a preferred choice to us...
- Christopher Wright (39/43) Dec 06 2007 The TailConst template would probably need to be a struct:
- Derek Parnell (38/55) Dec 06 2007 Which means for reference types, 'x' is modifiable but what it reference...
- Walter Bright (9/35) Dec 06 2007 My overriding concern with const is to have a useful, correct, and
- BCS (9/9) Dec 06 2007 totally random though: I'm designing a program and ran across a place wh...
- Walter Bright (7/14) Dec 06 2007 Since the point of a pointer is to dereference, perhaps a pointer is the...
- BCS (7/22) Dec 07 2007 In my case I have a table of info that I want to get things from, the
- sambeau (8/13) Dec 06 2007 Rather than re-using enum (and confusing me) why not use 'define' eg:-
- Walter Bright (3/7) Dec 06 2007 'define' has been proposed before. I'd prefer to stay away from it
- sambeau (6/8) Dec 06 2007 How about 'let' then?
- sambeau (7/11) Dec 06 2007 On reflection, I don't think that's a good reason at all.
- Christopher Wright (5/20) Dec 06 2007 Well, there are anonymous enums, right? /me hasn't used enums in quite
- Walter Bright (3/4) Dec 06 2007 Right. We already have:
- Leandro Lucarella (13/20) Dec 07 2007 Even when I find 'let' appealing, I think 'macro' is the way to go. It
- Paul Anderson (7/31) Dec 06 2007 I don't care for 'enum' used in this way. It distracts from (dilutes?) t...
- Bill Baxter (5/42) Dec 06 2007 That's not bad either. final, alias, macro -- they all make more sense
- sambeau (11/55) Dec 06 2007 how about replacing 'enum' with 'def'
- guslay (6/70) Dec 06 2007 I've always thought of enum a special case of constant value. Now I gues...
- Denton Cockburn (4/69) Dec 07 2007 You've mentioned this already, but D's already got too many keywords. I...
- guslay (3/8) Dec 07 2007 Having specific, obvious keywords for different concepts may cause less ...
- Denton Cockburn (7/21) Dec 07 2007 From the explanations of what enum actually does in D (which is differen...
- guslay (4/9) Dec 06 2007 const int x = 1;
- Kris (5/14) Dec 06 2007 all those Win32 constants actually adds over 50KB of bloat. Tango would ...
- guslay (2/22) Dec 06 2007 You're right, without whole program optimization it would probably only ...
- Don Clugston (3/19) Dec 07 2007 No, you can't, but IIRC Walter said that was actually a bug. Currently t...
- Walter Bright (4/5) Dec 08 2007 Yes, which is one of the problems with using const to declare manifest
As a result of all the const comments here, and some serious semantic problems discovered (dang it's hard to think of everything in advance), it seems there needs to be another tweak of the const behavior. Every time we try to sneak in "tail-const" in some form, some semantic correctness breaks somewhere. For example, struct member functions can be const or non-const, but there is no notion of "tail-const" for struct member functions. Trying to accommodate this results in all kinds of peculiar rules and inconsistencies. The second thing that just causes endless difficulties is the idea of using const to declare manifest constants, as in: const x = 3; having the same meaning as the C: #define x 3 in that 1) x does not consume storage and 2) x is typed as int, not const(int). For example, auto i = x; one would *not* want i to be typed as const(int). So, we're going to try a new, simpler regime: const T x; is semantically identical to: const(T) x; and the type of x is const(T). That leaves what to do about manifest constants. It occurs that we already have a mechanism for them - enums. So why not: enum x = 3; enum long y = 4; ? I think that solves our problem. There's one last problem: class C { } const(C)[] a; a[3] = new C(); // error, x[3] is const does not work with this new regime. Every twist we tried to make it work caused other problems. Eventually, it just became clear that this just is not going to work. But, the following does work: a ~= new C(); a = a[1..3]; a = b; just like for strings. One can copy, concatenate, and slice such arrays (just like for strings). It's not so bad. Andrei also mentioned the possibility of using a template: TailConst!(C)[] a; which would do whatever was necessary under the hood to allow the elements of a to be rebound while still keeping the contents of the C objects const.
Dec 06 2007
May I be the first to say I am very happy with everything you've said. Thank you. :-) On 12/6/07, Walter Bright <newshound1 digitalmars.com> wrote:There's one last problem: class C { } const(C)[] a; a[3] = new C(); // error, x[3] is const does not work with this new regime. Every twist we tried to make it work caused other problems.I understand the problem. Have you considered the possible solution which has been suggested on this group - a special syntax for classes having mutable refs to constant data? Under that suggestion, the above code would become: class C { } const(C)&[] a; a[3] = new C(); // OK It's the ampersand that makes it OK. It tells you that the reference is not constified. I think that would work, in exactly the same way that struct S { } struct(S)*[] a; a[3] = new S(); // OK works.Andrei also mentioned the possibility of using a template: TailConst!(C)[] a; which would do whatever was necessary under the hood to allow the elements of a to be rebound while still keeping the contents of the C objects const.That's kind of the same thing as const(C)&[] a, except with a template instead of an ampersand. Up to you which way you like more. Anyway, like I said, I'm happy. D is brilliant :-)
Dec 06 2007
Janice Caron wrote:I understand the problem. Have you considered the possible solution which has been suggested on this group - a special syntax for classes having mutable refs to constant data? Under that suggestion, the above code would become: class C { } const(C)&[] a; a[3] = new C(); // OK It's the ampersand that makes it OK. It tells you that the reference is not constified. I think that would work, in exactly the same way that struct S { } struct(S)*[] a; a[3] = new S(); // OK works.There are a couple problems with it, the worst of which is its impact on generic code: const(T)[] Would you put the & there or not? What would & mean if one wrote: struct S { C c; } const(S)&[] a; ? One principle we try to adhere to is that it should make sense to be able to wrap any type with a struct, and have it be possible for that struct to behave as if it were that member type. And finally, this suggests that & means "tail-const". Tail-const has that severe problem that there is no such thing as a tail-const member function (i.e. a member function that can modify the fields of the object, but not anything those fields refer to).Anyway, like I said, I'm happy.I'm glad!D is brilliant :-)
Dec 06 2007
On 12/6/07, Walter Bright <newshound1 digitalmars.com> wrote:There are a couple problems with it, the worst of which is its impact on generic code: const(T)[] Would you put the & there or not?Good point. You'd need it for a class, but not for a struct. I hadn't thought of that. That said, would that be much of a problem? Arrays of structs are very different beasts from arrays of class references. The copy semantics alone are different enough that one might imagine that generic code would need one or two if(is(T==struct))s in there anyway.What would & mean if one wrote: struct S { C c; } const(S)&[] a; ?I had in mind that that would be a syntax error.One principle we try to adhere to is that it should make sense to be able to wrap any type with a struct, and have it be possible for that struct to behave as if it were that member type.If we went with the & syntax, then that principle would dictate the requirement of an additional operator overload, which for want of a better name I shall temporarily call opAmpersand. (...which begs the question, which of opStar and opAmpersand has more right to be called opDeref... but let's worry about that later!)And finally, this suggests that & means "tail-const".I prefer to think that it means "reference to", in the same way that * means "pointer to". However, this is D, not C++, so the symbol would only be allowed for types which were /already references/, in which case it could be used to indicate tail constness by placing the symbol outside the brackets. Note that const(C&) would mean exactly the same thing as const(C) - so it's not the ampersand that means tail-const, it's its placement.Tail-const has that severe problem that there is no such thing as a tail-const member function (i.e. a member function that can modify the fields of the object, but not anything those fields refer to).Forgive me - perhaps I haven't thought this through deeply enough. I don't follow why that's a problem.
Dec 06 2007
Janice Caron wrote:On 12/6/07, Walter Bright <newshound1 digitalmars.com> wrote:I think it would be, especially from the point of view of generic programming.There are a couple problems with it, the worst of which is its impact on generic code: const(T)[] Would you put the & there or not?Good point. You'd need it for a class, but not for a struct. I hadn't thought of that. That said, would that be much of a problem?Arrays of structs are very different beasts from arrays of class references. The copy semantics alone are different enough that one might imagine that generic code would need one or two if(is(T==struct))s in there anyway.The less of such special casing the better <g>.A special syntax for class types means that one has to know that type T is a class.What would & mean if one wrote: struct S { C c; } const(S)&[] a; ?I had in mind that that would be a syntax error.You see how pulling on that string brings us more and more special cases and problems :-( I won't say this is impossible, but it's always something we can think about later after we have more experience with const.One principle we try to adhere to is that it should make sense to be able to wrap any type with a struct, and have it be possible for that struct to behave as if it were that member type.If we went with the & syntax, then that principle would dictate the requirement of an additional operator overload, which for want of a better name I shall temporarily call opAmpersand.If one has a tail-const struct, do you call the mutable member function or the const member function?And finally, this suggests that & means "tail-const".I prefer to think that it means "reference to", in the same way that * means "pointer to". However, this is D, not C++, so the symbol would only be allowed for types which were /already references/, in which case it could be used to indicate tail constness by placing the symbol outside the brackets. Note that const(C&) would mean exactly the same thing as const(C) - so it's not the ampersand that means tail-const, it's its placement.Tail-const has that severe problem that there is no such thing as a tail-const member function (i.e. a member function that can modify the fields of the object, but not anything those fields refer to).Forgive me - perhaps I haven't thought this through deeply enough. I don't follow why that's a problem.
Dec 06 2007
On 12/6/07, Walter Bright <newshound1 digitalmars.com> wrote:A special syntax for class types means that one has to know that type T is a class.andIf one has a tail-const struct, do you call the mutable member function or the const member function?Got it. I don't have a solution yet, but at least I know what to think about. If we can't have mutable-ref-to-const-class at all, as you say, it's not so bad. I'd say we can live without that. There are always other ways to code things. But I'll keep thinking. Thanks.
Dec 06 2007
"Walter Bright" wroteJanice Caron wrote:What happens if you have this? const(T)*[] If T is a struct, then it's fine, but if it's a class, then what? To me the situation is just as bad. This whole problem stems from the fact that a struct declaration is a value type and a class declaration is a reference type, but they look the same. You are never going to have a consistent syntax for generic const code because you don't have a consistent syntax for normal declarations. I see one good solution. A pointer/reference declarator that acts the same for both structs and classes. class C {} struct S {} C x; // a reference to a class S x; // a struct C& x; // a reference to a class (identical to C x) S& x; // a reference to a struct (identical to S * x) S& x = new S; // heap allocated struct C& x = new C; // heap allocated class const(C) x; // a const reference to a const C const C x; // identical to const(C) const(C)& x; // a mutable reference to a const C const(C)[] x; // an array of const references to const C instances const(C)&[] x; // an array of mutable references to const C instances const(S) x; // a const S. Cannot set x or x.member const S x; // identical to const(S) const(S)[] x; // an array of const S types const(S)*[] x; // an array of mutable references to const S types const(S)&[] x; // an array of mutable references to const S types (identical to const(S)*[]) you need generic tail-const code? use const(T)& you need generic fully-const code? use const(T) or use something else instead of &, I don't care. It just seems like this notion that I can now have tail-const structs, but not tail-const classes is just as bad, if not worse, than the original problem.I understand the problem. Have you considered the possible solution which has been suggested on this group - a special syntax for classes having mutable refs to constant data? Under that suggestion, the above code would become: class C { } const(C)&[] a; a[3] = new C(); // OK It's the ampersand that makes it OK. It tells you that the reference is not constified. I think that would work, in exactly the same way that struct S { } struct(S)*[] a; a[3] = new S(); // OK works.There are a couple problems with it, the worst of which is its impact on generic code: const(T)[] Would you put the & there or not? What would & mean if one wrote: struct S { C c; } const(S)&[] a; ?One principle we try to adhere to is that it should make sense to be able to wrap any type with a struct, and have it be possible for that struct to behave as if it were that member type.const (X)* m; Please tell me how you will replace m with a 'smart' pointer type that is mutable, but the pointer contents are not. Without using a template. Because using a Template, I can do it with my regime also :)And finally, this suggests that & means "tail-const". Tail-const has that severe problem that there is no such thing as a tail-const member function (i.e. a member function that can modify the fields of the object, but not anything those fields refer to).Huh? I thought tail-const was that you could change the reference but not the members? i.e. const(S)* x, I can change x but not x.member? -Steve
Dec 06 2007
Steven Schveighoffer wrote:What happens if you have this? const(T)*[]Array of pointers to constant T.If T is a struct, then it's fine, but if it's a class, then what? To me the situation is just as bad.It is perfectly consistent. I don't see why it is bad.This whole problem stems from the fact that a struct declaration is a value type and a class declaration is a reference type, but they look the same. You are never going to have a consistent syntax for generic const code because you don't have a consistent syntax for normal declarations.Having distinctly different value and reference aggregates is, in my opinion, a good thing.const (X)* m; Please tell me how you will replace m with a 'smart' pointer type that is mutable, but the pointer contents are not.That's the way it works now. You can modify m, but not X.Yes, that's exactly what tail-const is.And finally, this suggests that & means "tail-const". Tail-const has that severe problem that there is no such thing as a tail-const member function (i.e. a member function that can modify the fields of the object, but not anything those fields refer to).Huh? I thought tail-const was that you could change the reference but not the members?
Dec 06 2007
"Walter Bright" wroteSteven Schveighoffer wrote:const(T)*[] x; x[0].member is a struct member if T is a struct, what is it if T is a class? I was under the (possibly wrong) impression that this is illegal?What happens if you have this? const(T)*[]Array of pointers to constant T.If T is a struct, then it's fine, but if it's a class, then what? To me the situation is just as bad.It is perfectly consistent. I don't see why it is bad.I totally agree. I don't think struct variables should become references. I was saying there should be a way to mean "reference to either struct or class" to make generic code with tail-constness easier to writeThis whole problem stems from the fact that a struct declaration is a value type and a class declaration is a reference type, but they look the same. You are never going to have a consistent syntax for generic const code because you don't have a consistent syntax for normal declarations.Having distinctly different value and reference aggregates is, in my opinion, a good thing.Sure, but your original point was to be "able to wrap any type with a struct, and have it be possible for that struct to behave as if it were that member type". I believed you were implying that this was a reason NOT to have a & operator. My question to you is, how does having a reference operator make this more difficult than not having one? A reference is a pointer. We already have those, I have no reason to believe that they are any less wrappable than a pointer?const (X)* m; Please tell me how you will replace m with a 'smart' pointer type that is mutable, but the pointer contents are not.That's the way it works now. You can modify m, but not X.OK, I am confused, isn't const(S)* tail const? And if so, how does this new scheme rid us of tail const? Couldn't I use this to call a const member function on a struct? The way I am interpreting your new const is that I can have tail-const for struct references (pointers) but not tail-const for class references. It seems to me it would be more important to have classes be const, why is your new way better? In other words, I can create a tail-const struct array via: const(S)*[] tailconst; tailconst[0] = new S; // ok to assign to tailconst[0] tailconst[0].nonconstfunc; // error, cannot call const function How do I do the same for a class? I don't want to have to use a * operator because I don't have to do that for structs. I want to make generic code. -SteveYes, that's exactly what tail-const is.And finally, this suggests that & means "tail-const". Tail-const has that severe problem that there is no such thing as a tail-const member function (i.e. a member function that can modify the fields of the object, but not anything those fields refer to).Huh? I thought tail-const was that you could change the reference but not the members?
Dec 06 2007
Steven Schveighoffer wrote:"Walter Bright" wroteI don't understand. Exactly what is illegal?Steven Schveighoffer wrote:const(T)*[] x; x[0].member is a struct member if T is a struct, what is it if T is a class? I was under the (possibly wrong) impression that this is illegal?What happens if you have this? const(T)*[]Array of pointers to constant T.If T is a struct, then it's fine, but if it's a class, then what? To me the situation is just as bad.It is perfectly consistent. I don't see why it is bad.Sure, but your original point was to be "able to wrap any type with a struct, and have it be possible for that struct to behave as if it were that member type". I believed you were implying that this was a reason NOT to have a & operator. My question to you is, how does having a reference operator make this more difficult than not having one? A reference is a pointer.There's the problem we're having. While a class reference is implemented as a pointer 'under the hood', to the type system, it is not a pointer.OK, I am confused, isn't const(S)* tail const?No. For const(int*), tail const of that construct would mean that the pointer is mutable while what it points to is not.And if so, how does this new scheme rid us of tail const?It would say that const(int*) would mean an immutable pointer to an immutable int.Couldn't I use this to call a const member function on a struct?I'm very confused as to what you're referring to.The way I am interpreting your new const is that I can have tail-const for struct references (pointers) but not tail-const for class references.No. The correct interpretation is that all parts of the type within the ( ) are immutable.In other words, I can create a tail-const struct array via: const(S)*[] tailconst; tailconst[0] = new S; // ok to assign to tailconst[0] tailconst[0].nonconstfunc; // error, cannot call const function How do I do the same for a class?You cannot separate the class reference from the class fields.
Dec 06 2007
"Walter Bright" wroteSteven Schveighoffer wrote:I guess it isn't :) I thought: class C { void f() {} } C c = new C; C *cp = &c; cp.f(); // I thought this was illegal, but it works! So you CAN still have tail-const. The only issue is that you need to have a reference to take the address of... It would be nice if I could just do: C * cp = new C; Then I could have generic code like: const(T)*[] x x = new const(T)*[5] for(int i = 0; i < 5; i++) x[i] = new T; // this will work for structs, not for classes then we have functionally tail-const back... I think this isn't going to be possible, because then you have no way of specifying I want a reference of a reference. Like a ref parameter. This is why I proposed that the & operator is used to mean 'pointer to'. The benefit is: T x; // for classes, this means pointer, for structs, it means value T *x; // for classes, this means pointer to pointer, for structs it means pointer. T &x; // for classes, it means pointer, for structs, it means pointer"Walter Bright" wroteI don't understand. Exactly what is illegal?Steven Schveighoffer wrote:const(T)*[] x; x[0].member is a struct member if T is a struct, what is it if T is a class? I was under the (possibly wrong) impression that this is illegal?What happens if you have this? const(T)*[]Array of pointers to constant T.If T is a struct, then it's fine, but if it's a class, then what? To me the situation is just as bad.It is perfectly consistent. I don't see why it is bad.I believe I understand your confusion. To me tail-const == reference is mutable, pointed to data is not. I think of this as the semantic meaning of tail-const regardless of what the syntax says To you, tail-const is the specific syntax of const(C) for a reference type meaning C is tail-const. I agree that this is confusing, and bad for generic code. But const(C)* under the new regime is still functionally tail-const, is it not?Sure, but your original point was to be "able to wrap any type with a struct, and have it be possible for that struct to behave as if it were that member type". I believed you were implying that this was a reason NOT to have a & operator. My question to you is, how does having a reference operator make this more difficult than not having one? A reference is a pointer.There's the problem we're having. While a class reference is implemented as a pointer 'under the hood', to the type system, it is not a pointer.OK, I am confused, isn't const(S)* tail const?No. For const(int*), tail const of that construct would mean that the pointer is mutable while what it points to is not.I was confused also :) I think the new regime allows tail const, but makes it difficult to make tail-const references to classes.And if so, how does this new scheme rid us of tail const?It would say that const(int*) would mean an immutable pointer to an immutable int.Couldn't I use this to call a const member function on a struct?I'm very confused as to what you're referring to.I understand this and agree with it.The way I am interpreting your new const is that I can have tail-const for struct references (pointers) but not tail-const for class references.No. The correct interpretation is that all parts of the type within the ( ) are immutable.That is why I proposed a new syntax. If you want to do const in a way that is correct and backwards compatible, I think you cannot avoid this. To allow for more power for structs to easily have tail const, but not classes seems very wrong to me. -SteveIn other words, I can create a tail-const struct array via: const(S)*[] tailconst; tailconst[0] = new S; // ok to assign to tailconst[0] tailconst[0].nonconstfunc; // error, cannot call const function How do I do the same for a class?You cannot separate the class reference from the class fields.
Dec 07 2007
Walter Bright wrote:As a result of all the const comments here, and some serious semantic problems discovered (dang it's hard to think of everything in advance), it seems there needs to be another tweak of the const behavior. Every time we try to sneak in "tail-const" in some form, some semantic correctness breaks somewhere. For example, struct member functions can be const or non-const, but there is no notion of "tail-const" for struct member functions. Trying to accommodate this results in all kinds of peculiar rules and inconsistencies. The second thing that just causes endless difficulties is the idea of using const to declare manifest constants, as in: const x = 3; having the same meaning as the C: #define x 3 in that 1) x does not consume storage and 2) x is typed as int, not const(int). For example, auto i = x; one would *not* want i to be typed as const(int).Makes sense.So, we're going to try a new, simpler regime: const T x; is semantically identical to: const(T) x; and the type of x is const(T). That leaves what to do about manifest constants. It occurs that we already have a mechanism for them - enums. So why not: enum x = 3; enum long y = 4; ? I think that solves our problem.One thing that concerns me. If we assume that "enum x = 3" is simply shorthand for "enum { x = 3 }" then all such declarations would be implicitly typed as integers, which doesn't sound like you want. It seems you're suggesting "enum" be treated more like a storage class here? I'm not sure if I like that idea.There's one last problem: class C { } const(C)[] a; a[3] = new C(); // error, x[3] is constAs I see it, an array of objects can have two levels of const-ness: 1. The array itself is const and may not be resized or have its contents changed. 2. The array is not const but its elements are, so the array may be resized, but only const member functions may be called on the contained objects. To me, "const(C)[]" looks like case 2, because only the element type is in parenthesis. Thus "const C[]" or "const (C[])" would both represent case 1. However, this is obviously not how things currently work. I this has something to do with the desire to shoehorn tail const into the design, but it doesn't feel natural to me. Can you explain why it works the way it does? Sean
Dec 06 2007
Sean Kelly wrote:Walter Bright wrote:It would be implicitly typed to the type of its initializer, or you can give a type. Yes, it would behave like a storage class.That leaves what to do about manifest constants. It occurs that we already have a mechanism for them - enums. So why not: enum x = 3; enum long y = 4; ? I think that solves our problem.One thing that concerns me. If we assume that "enum x = 3" is simply shorthand for "enum { x = 3 }" then all such declarations would be implicitly typed as integers, which doesn't sound like you want.Right, but under the new regime, that is how they would work.There's one last problem: class C { } const(C)[] a; a[3] = new C(); // error, x[3] is constAs I see it, an array of objects can have two levels of const-ness: 1. The array itself is const and may not be resized or have its contents changed. 2. The array is not const but its elements are, so the array may be resized, but only const member functions may be called on the contained objects. To me, "const(C)[]" looks like case 2, because only the element type is in parenthesis. Thus "const C[]" or "const (C[])" would both represent case 1. However, this is obviously not how things currently work.I this has something to do with the desire to shoehorn tail const into the design, but it doesn't feel natural to me. Can you explain why it works the way it does?I've given up on tail const in any of its forms. The new regime has no tail const, no head const, it's just const, and fully transitive const at that.
Dec 06 2007
Walter Bright wrote:So if I have: const(Foo)* t; the pointer is const and points to a const Foo? What about this: template Ptr(T) { alias T* Ptr; } Ptr!(const(Foo)) t; If I have a template method that says: void Something (T)() { T[] stuff = new T[5]; stuff[2] = T.init; } Something!(const(Foo)); Will that fail?1. The array itself is const and may not be resized or have its contents changed. 2. The array is not const but its elements are, so the array may be resized, but only const member functions may be called on the contained objects. To me, "const(C)[]" looks like case 2, because only the element type is in parenthesis. Thus "const C[]" or "const (C[])" would both represent case 1. However, this is obviously not how things currently work.Right, but under the new regime, that is how they would work.I this has something to do with the desire to shoehorn tail const into the design, but it doesn't feel natural to me. Can you explain why it works the way it does?I've given up on tail const in any of its forms. The new regime has no tail const, no head const, it's just const, and fully transitive const at that.
Dec 06 2007
Christopher Wright wrote:No, it is a mutable pointer to a const Foo. A const pointer to a const Foo would be: const(Foo*) t;I've given up on tail const in any of its forms. The new regime has no tail const, no head const, it's just const, and fully transitive const at that.So if I have: const(Foo)* t; the pointer is const and points to a const Foo?What about this: template Ptr(T) { alias T* Ptr; } Ptr!(const(Foo)) t; If I have a template method that says: void Something (T)() { T[] stuff = new T[5]; stuff[2] = T.init; } Something!(const(Foo)); Will that fail?Yes, because T[] will be the same thing as const(Foo)[]. Hiding it behind an alias and a template won't change that <g>.
Dec 06 2007
Walter Bright wrote:Christopher Wright wrote:So why do arrays take their const status from their elements when pointers don't?No, it is a mutable pointer to a const Foo. A const pointer to a const Foo would be: const(Foo*) t;I've given up on tail const in any of its forms. The new regime has no tail const, no head const, it's just const, and fully transitive const at that.So if I have: const(Foo)* t; the pointer is const and points to a const Foo?Will that fail?Yes, because T[] will be the same thing as const(Foo)[]. Hiding it behind an alias and a template won't change that <g>.
Dec 06 2007
Christopher Wright wrote:Walter Bright wrote:??? I think there's a misunderstanding here on what arrays are. Arrays consist of a pointer/length pair. As far as const goes, they are just like pointers.Christopher Wright wrote:So why do arrays take their const status from their elements when pointers don't?No, it is a mutable pointer to a const Foo. A const pointer to a const Foo would be: const(Foo*) t;I've given up on tail const in any of its forms. The new regime has no tail const, no head const, it's just const, and fully transitive const at that.So if I have: const(Foo)* t; the pointer is const and points to a const Foo?Will that fail?Yes, because T[] will be the same thing as const(Foo)[]. Hiding it behind an alias and a template won't change that <g>.
Dec 06 2007
Walter Bright wrote:Christopher Wright wrote:But I can reassign a const Foo, right?Walter Bright wrote:??? I think there's a misunderstanding here on what arrays are. Arrays consist of a pointer/length pair. As far as const goes, they are just like pointers.Christopher Wright wrote:So why do arrays take their const status from their elements when pointers don't?No, it is a mutable pointer to a const Foo. A const pointer to a const Foo would be: const(Foo*) t;I've given up on tail const in any of its forms. The new regime has no tail const, no head const, it's just const, and fully transitive const at that.So if I have: const(Foo)* t; the pointer is const and points to a const Foo?Will that fail?Yes, because T[] will be the same thing as const(Foo)[]. Hiding it behind an alias and a template won't change that <g>.
Dec 07 2007
Walter Bright wrote:Sean Kelly wrote:I can't say I'm terribly fond of using "enum" for this, but it is certainly closer than any other language feature to what you want. However, I am still questioning the need for a new keyword here. Is it that the user may sometimes want type inference to pick up the const qualifier and not other times? Or would they never want the const qualifier to be picked up? If it's the former, then perhaps some rule could be established where the user would never want const to be preserved? For example, I can't see ever wanting it for basic data types like integers, but I might generally want it for classes. I suppose what I'm wondering is if this may be one instance where the ideas of head and tail const apply without causing too many problems?Walter Bright wrote:It would be implicitly typed to the type of its initializer, or you can give a type. Yes, it would behave like a storage class.That leaves what to do about manifest constants. It occurs that we already have a mechanism for them - enums. So why not: enum x = 3; enum long y = 4; ? I think that solves our problem.One thing that concerns me. If we assume that "enum x = 3" is simply shorthand for "enum { x = 3 }" then all such declarations would be implicitly typed as integers, which doesn't sound like you want.Oh okay. Then I'm all for it, at least in theory. :-)Right, but under the new regime, that is how they would work.There's one last problem: class C { } const(C)[] a; a[3] = new C(); // error, x[3] is constAs I see it, an array of objects can have two levels of const-ness: 1. The array itself is const and may not be resized or have its contents changed. 2. The array is not const but its elements are, so the array may be resized, but only const member functions may be called on the contained objects. To me, "const(C)[]" looks like case 2, because only the element type is in parenthesis. Thus "const C[]" or "const (C[])" would both represent case 1. However, this is obviously not how things currently work.This is unfortunate, but probably for the best. SeanI this has something to do with the desire to shoehorn tail const into the design, but it doesn't feel natural to me. Can you explain why it works the way it does?I've given up on tail const in any of its forms. The new regime has no tail const, no head const, it's just const, and fully transitive const at that.
Dec 06 2007
Sean Kelly wrote:I can't say I'm terribly fond of using "enum" for this, but it is certainly closer than any other language feature to what you want. However, I am still questioning the need for a new keyword here. Is it that the user may sometimes want type inference to pick up the const qualifier and not other times?Yes for that reason, and the other reason is one rarely wants storage allocated for manifest constants. windows.d has 10,000 declarations in it, who wants 40K of executable bloat from const declarations?Or would they never want the const qualifier to be picked up?That was my thought, but this has two fatal problems with it: 1) you have to pick up the const qualifier if it's a struct, because the struct may wrap a class reference. Thus, structs would not behave like the underlying types. 2) Andrei pointed out that C++ (which drops the 'head const') is having severe problems with template metaprogramming over this, i.e. it becomes impractical to write "forwarder templates".If it's the former, then perhaps some rule could be established where the user would never want const to be preserved? For example, I can't see ever wanting it for basic data types like integers, but I might generally want it for classes. I suppose what I'm wondering is if this may be one instance where the ideas of head and tail const apply without causing too many problems?Unfortunately, they do cause problems. For example, struct S1 { int x; } struct S2 { int* p; : What does const mean for S1 and S2? Should it be stripped for one and not the other?
Dec 06 2007
Walter Bright wrote:Sean Kelly wrote:Oops, one last thing. Does the transitivity mean it would be impossible to have a const array of references to mutable data? SeanWalter Bright wrote:Right, but under the new regime, that is how they would work.There's one last problem: class C { } const(C)[] a; a[3] = new C(); // error, x[3] is constAs I see it, an array of objects can have two levels of const-ness: 1. The array itself is const and may not be resized or have its contents changed. 2. The array is not const but its elements are, so the array may be resized, but only const member functions may be called on the contained objects. To me, "const(C)[]" looks like case 2, because only the element type is in parenthesis. Thus "const C[]" or "const (C[])" would both represent case 1. However, this is obviously not how things currently work.I this has something to do with the desire to shoehorn tail const into the design, but it doesn't feel natural to me. Can you explain why it works the way it does?I've given up on tail const in any of its forms. The new regime has no tail const, no head const, it's just const, and fully transitive const at that.
Dec 06 2007
Sean Kelly wrote:Oops, one last thing. Does the transitivity mean it would be impossible to have a const array of references to mutable data?Yes.
Dec 06 2007
Sean Kelly wrote:One thing that concerns me. If we assume that "enum x = 3" is simply shorthand for "enum { x = 3 }" then all such declarations would be implicitly typed as integers, which doesn't sound like you want. It seems you're suggesting "enum" be treated more like a storage class here? I'm not sure if I like that idea.Why not macro x = 3; ?
Dec 06 2007
Ary Borenszweig wrote:Sean Kelly wrote:Assuming that we need a new keyword, I like "macro" better. We're going to get it in 2.0 anyway, right? SeanOne thing that concerns me. If we assume that "enum x = 3" is simply shorthand for "enum { x = 3 }" then all such declarations would be implicitly typed as integers, which doesn't sound like you want. It seems you're suggesting "enum" be treated more like a storage class here? I'm not sure if I like that idea.Why not macro x = 3;
Dec 06 2007
Sean Kelly wrote:Ary Borenszweig wrote:That's the idea. ;-) There a good use right there for that keyword.Sean Kelly wrote:Assuming that we need a new keyword, I like "macro" better. We're going to get it in 2.0 anyway, right?One thing that concerns me. If we assume that "enum x = 3" is simply shorthand for "enum { x = 3 }" then all such declarations would be implicitly typed as integers, which doesn't sound like you want. It seems you're suggesting "enum" be treated more like a storage class here? I'm not sure if I like that idea.Why not macro x = 3;
Dec 06 2007
On Thu, 06 Dec 2007 18:45:38 -0300, Ary Borenszweig wrote:Ary Borenszweig wrote:Why not macro x = 3;There a good use right there for that keyword.I agree. And I would still like to be able to group such definition together such as ... macro { x = 3; y = "qwerty"; z = 61.74; } -- Derek (skype: derek.j.parnell) Melbourne, Australia 7/12/2007 11:22:25 AM
Dec 06 2007
Ary Borenszweig wrote:Why not macro x = 3; ?It's been suggested several times. It doesn't make much aesthetic sense to do things like: macro int x = 3;
Dec 06 2007
On Thu, 06 Dec 2007 16:57:20 -0800, Walter Bright wrote:Ary Borenszweig wrote:Why not macro x = 3; ?It's been suggested several times.I definitely think that overloading 'enum' to declare definitions is quite a lot worse than overloading 'macro' or 'alias'.It doesn't make much aesthetic sense to do things like: macro int x = 3;It doesn't?!? On what authority have you made that assertion? I makes perfectly good aesthetic sense to me, more so than 'enum'. enum defname = "upload.log"; is NOT an enumeration as there is no numbers involved. macro defname = "upload.log"; looks more pleasing and grokable IMNSHO. And what do you say about the idea to group together such definitions? macro { a = 3; b = "qwerty"; c = 61.74; } rather than ... macro a = 3; macro b = "qwerty"; macro c = 61.74; -- Derek (skype: derek.j.parnell) Melbourne, Australia 7/12/2007 12:16:16 PM
Dec 06 2007
Walter Bright wrote:Ary Borenszweig wrote:Well, macros like that would almost always refer to primitive types: ints, bools, strings, etc. So the type will be ommited most of the time. I can't come up with an example for a constant (like #define) that needs to declare it's type (in fact, #define doesn't declare a type). If it's an enum, you would say macro foo = SomeEnum.value; If it's a constant field in a type, it's the same way. If you want to have some constant initialized in a "static this", than it can't be done with the macro syntax.Why not macro x = 3; ?It's been suggested several times. It doesn't make much aesthetic sense to do things like: macro int x = 3;
Dec 06 2007
Walter Bright wrote:Ary Borenszweig wrote:So are you saying that it would be fine without the type qualifier, or that you don't like the use of "macro" here at all?Why not macro x = 3; ?It's been suggested several times. It doesn't make much aesthetic sense to do things like: macro int x = 3;
Dec 06 2007
Sean Kelly wrote:Walter Bright wrote:Since the optional type qualifier should be supported, it doesn't make sense.Ary Borenszweig wrote:So are you saying that it would be fine without the type qualifier, or that you don't like the use of "macro" here at all?Why not macro x = 3; ?It's been suggested several times. It doesn't make much aesthetic sense to do things like: macro int x = 3;
Dec 06 2007
Walter Bright wrote:Sean Kelly wrote:It may be stretching the desire to use "macro" too far, but casting could be used to specify the type: macro x = 5L; // long int macro y = cast(short) 2; macro z = "abc"w; Thus it wouldn't actually be treated like a storage class. That might also save some confusion for things like: enum const static int x = 7;Walter Bright wrote:Since the optional type qualifier should be supported, it doesn't make sense.Ary Borenszweig wrote:So are you saying that it would be fine without the type qualifier, or that you don't like the use of "macro" here at all?Why not macro x = 3; ?It's been suggested several times. It doesn't make much aesthetic sense to do things like: macro int x = 3;
Dec 07 2007
Sean Kelly wrote:It may be stretching the desire to use "macro" too far, but casting could be used to specify the type: macro x = 5L; // long int macro y = cast(short) 2; macro z = "abc"w;Yes, it could be. But I just can't see it being a preferred choice to use: macro y = cast(short) 2; rather than: enum short y = 2; as the latter is how declarations work (setting aside the use of 'enum' for the moment). There is a reasonable school of thought that says that the use of casting should be minimized, and that every cast should be scrutinized (since it is a meataxe rather than a scalpel). Having too many casts in regular use will hide the questionable uses.Thus it wouldn't actually be treated like a storage class. That might also save some confusion for things like: enum const static int x = 7;That wouldn't be allowed any more than: typedef static int x = 7; because it makes no sense.
Dec 08 2007
Walter Bright wrote:TailConst!(C)[] a; which would do whatever was necessary under the hood to allow the elements of a to be rebound while still keeping the contents of the C objects const.The TailConst template would probably need to be a struct: struct TailConst (T) { static if (is (T == class) || is (T == interface)) { // can just store a reference } else { // assignment mallocs some memory and copies arg onto heap // store a ptr } } And then we'd need an opDot if we wanted transparent access. It's an annoyance, but a minor one, to have to use opDeref. But I think perhaps the problem with arrays is that there's no way to say the array is not const, but its members are. The obvious syntax would be: const(Foo)[] foos = new const(Foo)[5]; foos[2] = new Foo(); // ok const(Foo[]) cfoos = new Foo[5]; cfoos[3] = new Foo(); // error; cfoos is const Then string would be an alias to invariant(char[]) rather than invariant(char)[], which makes sense. It's not a mutable array of invariant characters. However, this would suggest: const(const(Foo)[]) ccfoos; Which would suggest the cfoos array is a const buffer, but if it holds reference types, they are not const. And if the array is const, you can't rebind its elements. The solution to that mess, if you need transitive const, is to define const(T[]) to be the same as const(const(T)[]), which won't affect primitives and value types but will get the desired result for reference types. But it doesn't make sense to consider an array const if its elements are const; that would be extremely annoying with templates. If you wanted to use arrays for anything nontrivial, you'd have to start it with: static if (is (T == const)) { alias TailConst!(T) ElemType; } else { alias T ElemType; }
Dec 06 2007
On Thu, 06 Dec 2007 13:33:46 -0800, Walter Bright wrote:As a result of all the const comments here, and some serious semantic problems discovered (dang it's hard to think of everything in advance), it seems there needs to be another tweak of the const behavior.I'm glad you're flexible ;-)So, we're going to try a new, simpler regime: const T x; is semantically identical to: const(T) x; and the type of x is const(T).Which means for reference types, 'x' is modifiable but what it references is not modifiable. And for non-reference types, 'x' is not modifiable. So in some cases 'x' can be changed but in some cases it can't. Is that going to be a problem? const int x; // Can't change 'x' const int[] y; // Can change 'y' but not y[n]That leaves what to do about manifest constants. It occurs that we already have a mechanism for them - enums. So why not: enum x = 3; enum long y = 4; ? I think that solves our problem.An additional requirement, I guess, was to avoid creating a new keyword. In that case, the 'alias' keyword could also be overloaded to perform this role. alias x = 3; alias long y = 4; alias real pi = 3.14159265358979; especially in syntax forms that 'enum' would have problems with ... alias { x = 3; long y = 4; real pi = 3.14159265358979; }There's one last problem: class C { } const(C)[] a; a[3] = new C(); // error, x[3] is constI see, but in the new regime, doesn't this mean that both 'a' and what it refers to are const? Or would that be written ... const ( (C)[]) a; and thus what does this mean ... const (C[]) a; To summarize, we can write ... const C[] a; const (C)[] a; const (C[]) a; const ((C)[]) a; What will each of these forms signify? -- Derek (skype: derek.j.parnell) Melbourne, Australia 7/12/2007 9:44:43 AM
Dec 06 2007
Derek Parnell wrote:On Thu, 06 Dec 2007 13:33:46 -0800, Walter Bright wrote:My overriding concern with const is to have a useful, correct, and workable system!As a result of all the const comments here, and some serious semantic problems discovered (dang it's hard to think of everything in advance), it seems there needs to be another tweak of the const behavior.I'm glad you're flexible ;-)No, it means whatever part of the type is inside the () is not modifiable.So, we're going to try a new, simpler regime: const T x; is semantically identical to: const(T) x; and the type of x is const(T).Which means for reference types, 'x' is modifiable but what it references is not modifiable.And for non-reference types, 'x' is not modifiable. So in some cases 'x' can be changed but in some cases it can't. Is that going to be a problem? const int x; // Can't change 'x' const int[] y; // Can change 'y' but not y[n]With these, neither x, y, nor y[n] are mutable.const C[] a;a is a const array of const C.const (C)[] a;a is an array of const C.const (C[]) a;a is a const array of const C.const ((C)[]) a;a is a const array of const C.
Dec 06 2007
totally random though: I'm designing a program and ran across a place where I want to say "this pointer shall never be dereferenced, it shall only be used as an identity" the idea being that I want to be sure that the code has no dependencies on anything under it. It would be used somthing like a key in a hash table but where the test is "same thing" not "equal things". What should this be implemented as? Does this have any place in the const system? Is there an existing clean solution? I'm putting this out more as food for though than as a serious suggestion or request for thoughts on how to implement stuff in my case.
Dec 06 2007
BCS wrote:totally random though: I'm designing a program and ran across a place where I want to say "this pointer shall never be dereferenced, it shall only be used as an identity" the idea being that I want to be sure that the code has no dependencies on anything under it. It would be used somthing like a key in a hash table but where the test is "same thing" not "equal things". What should this be implemented as? Does this have any place in the const system? Is there an existing clean solution?Since the point of a pointer is to dereference, perhaps a pointer is the wrong thing. Perhaps it should be a struct. --------------------------------------------- Doolittle: "Bomb, what is your purpose?" -- Dark Star
Dec 06 2007
Walter Bright wrote:BCS wrote:In my case I have a table of info that I want to get things from, the things to be got are associated with object that are available to the caller. If I don't use the object pointers, then I need to add some process unique ID to the objects as handles. The pointer is good enough except that I want to drop the implies functional dependency. I might try typedefs of void* but that seems hackish.totally random though: I'm designing a program and ran across a place where I want to say "this pointer shall never be dereferenced, it shall only be used as an identity" the idea being that I want to be sure that the code has no dependencies on anything under it. It would be used somthing like a key in a hash table but where the test is "same thing" not "equal things". What should this be implemented as? Does this have any place in the const system? Is there an existing clean solution?Since the point of a pointer is to dereference, perhaps a pointer is the wrong thing. Perhaps it should be a struct.
Dec 07 2007
Walter Bright Wrote:That leaves what to do about manifest constants. It occurs that we already have a mechanism for them - enums. So why not: enum x = 3; enum long y = 4; ? I think that solves our problem.Rather than re-using enum (and confusing me) why not use 'define' eg:- define x = 3; define long y = 4; You can then a) emphasise 'definite' in the docs: "Having distinct limits", "Indisputable; certain", "Clearly defined; explicitly precise" while b) comforting C users.
Dec 06 2007
sambeau wrote:Rather than re-using enum (and confusing me) why not use 'define' eg:- define x = 3; define long y = 4;'define' has been proposed before. I'd prefer to stay away from it because of the negative connotations of C's preprocessor.
Dec 06 2007
Walter Bright Wrote:'define' has been proposed before. I'd prefer to stay away from it because of the negative connotations of C's preprocessor.How about 'let' then? It works for FP.. Or just 'def': it is a good short version of 'definite' in the way that 'int' is short for 'integer' and 'const' is short for 'constant'. different to '#define'. s
Dec 06 2007
sambeau Wrote:Walter Bright Wrote:On reflection, I don't think that's a good reason at all. The principal of least surprise is, I feel, more important. 'enum' was, in my opinion, always a slightly dodgily named construct at the best of times. Enumeration, to me, implies more than one thing. I feel, with all due respect (and a lot of deference) :-), that you are being a language implementor, looking at the guts of your implementation and asking "what else is this like?" rather than asking yourself (as a language designer) and saying "how best can I express this concept using terms most people will understand". Enum is just weird in this respect. It feels wrong.I'd prefer to stay away from it because of the negative connotations of C's preprocessor.
Dec 06 2007
sambeau wrote:sambeau Wrote:Well, there are anonymous enums, right? /me hasn't used enums in quite some time. So it's just letting you use all primitives with an enum, not just arithmetic types.Walter Bright Wrote:On reflection, I don't think that's a good reason at all. The principal of least surprise is, I feel, more important. 'enum' was, in my opinion, always a slightly dodgily named construct at the best of times. Enumeration, to me, implies more than one thing. I feel, with all due respect (and a lot of deference) :-), that you are being a language implementor, looking at the guts of your implementation and asking "what else is this like?" rather than asking yourself (as a language designer) and saying "how best can I express this concept using terms most people will understand". Enum is just weird in this respect. It feels wrong.I'd prefer to stay away from it because of the negative connotations of C's preprocessor.
Dec 06 2007
Christopher Wright wrote:Well, there are anonymous enums, right?Right. We already have: enum { x = 3 }
Dec 06 2007
sambeau, el 6 de diciembre a las 20:53 me escribiste:Walter Bright Wrote:Even when I find 'let' appealing, I think 'macro' is the way to go. It doesn't introduce a new keyword ('macro' is a keyword since DMD 1.011) and is something it got rewriten/processed by the compiler at compile-time. -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- ¿Qué será lo que hace que una brújula siempre marque el norte? - Ser aguja, nada más, y cumplir su misión. -- Ricardo Vaporeso'define' has been proposed before. I'd prefer to stay away from it because of the negative connotations of C's preprocessor.How about 'let' then? It works for FP..
Dec 07 2007
Walter Bright Wrote:That leaves what to do about manifest constants. It occurs that we already have a mechanism for them - enums. So why not: enum x = 3; enum long y = 4; ? I think that solves our problem. There's one last problem: class C { } const(C)[] a; a[3] = new C(); // error, x[3] is const does not work with this new regime. Every twist we tried to make it work caused other problems. Eventually, it just became clear that this just is not going to work. But, the following does work: a ~= new C(); a = a[1..3]; a = b; just like for strings. One can copy, concatenate, and slice such arrays (just like for strings). It's not so bad. Andrei also mentioned the possibility of using a template: TailConst!(C)[] a; which would do whatever was necessary under the hood to allow the elements of a to be rebound while still keeping the contents of the C objects const.I don't care for 'enum' used in this way. It distracts from (dilutes?) the meaning as an enumerated type. How about final? final x = 3; final real y = 7.5; 'final' is already a keyword and it's already used to declare one flavor of const in Java. Paul
Dec 06 2007
Paul Anderson wrote:Walter Bright Wrote:That's not bad either. final, alias, macro -- they all make more sense than reusing 'enum' for manifest constants that aren't really enumerating anything. --bbThat leaves what to do about manifest constants. It occurs that we already have a mechanism for them - enums. So why not: enum x = 3; enum long y = 4; ? I think that solves our problem. There's one last problem: class C { } const(C)[] a; a[3] = new C(); // error, x[3] is const does not work with this new regime. Every twist we tried to make it work caused other problems. Eventually, it just became clear that this just is not going to work. But, the following does work: a ~= new C(); a = a[1..3]; a = b; just like for strings. One can copy, concatenate, and slice such arrays (just like for strings). It's not so bad. Andrei also mentioned the possibility of using a template: TailConst!(C)[] a; which would do whatever was necessary under the hood to allow the elements of a to be rebound while still keeping the contents of the C objects const.I don't care for 'enum' used in this way. It distracts from (dilutes?) the meaning as an enumerated type. How about final? final x = 3; final real y = 7.5; 'final' is already a keyword and it's already used to declare one flavor of const in Java. Paul
Dec 06 2007
Bill Baxter Wrote:Paul Anderson wrote:how about replacing 'enum' with 'def' def X { A, B, C } def { A, B = 5+7, C, D = 8, E } def int A = 0; def int B = 1; def int C = 2; def x = 3; def long y = 4; Then we aren't changing the implementation, just the semantics so that they fit the implementation better. ... thoughts?Walter Bright Wrote:That's not bad either. final, alias, macro -- they all make more sense than reusing 'enum' for manifest constants that aren't really enumerating anything. --bbThat leaves what to do about manifest constants. It occurs that we already have a mechanism for them - enums. So why not: enum x = 3; enum long y = 4; ? I think that solves our problem. There's one last problem: class C { } const(C)[] a; a[3] = new C(); // error, x[3] is const does not work with this new regime. Every twist we tried to make it work caused other problems. Eventually, it just became clear that this just is not going to work. But, the following does work: a ~= new C(); a = a[1..3]; a = b; just like for strings. One can copy, concatenate, and slice such arrays (just like for strings). It's not so bad. Andrei also mentioned the possibility of using a template: TailConst!(C)[] a; which would do whatever was necessary under the hood to allow the elements of a to be rebound while still keeping the contents of the C objects const.I don't care for 'enum' used in this way. It distracts from (dilutes?) the meaning as an enumerated type. How about final? final x = 3; final real y = 7.5; 'final' is already a keyword and it's already used to declare one flavor of const in Java. Paul
Dec 06 2007
I've always thought of enum a special case of constant value. Now I guess constants will become a special case of enum? But seriously, I hope that in the end we will agree on the preferred way to define a constant value (of which we are not interested in taking the address of). Currently there is const/invariant int, which take storage and in this specific case are so completely redundant that I never know which one to use. There is enum, which has all the requirement but feels odd to generalize (as suggested if enum was spelled "let" or "def" there would be no problem using it for both enumerations and constant values). So whatever syntax is chosen, I hope it's the last! gus sambeau Wrote:Bill Baxter Wrote:Paul Anderson wrote:how about replacing 'enum' with 'def' def X { A, B, C } def { A, B = 5+7, C, D = 8, E } def int A = 0; def int B = 1; def int C = 2; def x = 3; def long y = 4; Then we aren't changing the implementation, just the semantics so that they fit the implementation better. ... thoughts?Walter Bright Wrote:That's not bad either. final, alias, macro -- they all make more sense than reusing 'enum' for manifest constants that aren't really enumerating anything. --bbThat leaves what to do about manifest constants. It occurs that we already have a mechanism for them - enums. So why not: enum x = 3; enum long y = 4; ? I think that solves our problem. There's one last problem: class C { } const(C)[] a; a[3] = new C(); // error, x[3] is const does not work with this new regime. Every twist we tried to make it work caused other problems. Eventually, it just became clear that this just is not going to work. But, the following does work: a ~= new C(); a = a[1..3]; a = b; just like for strings. One can copy, concatenate, and slice such arrays (just like for strings). It's not so bad. Andrei also mentioned the possibility of using a template: TailConst!(C)[] a; which would do whatever was necessary under the hood to allow the elements of a to be rebound while still keeping the contents of the C objects const.I don't care for 'enum' used in this way. It distracts from (dilutes?) the meaning as an enumerated type. How about final? final x = 3; final real y = 7.5; 'final' is already a keyword and it's already used to declare one flavor of const in Java. Paul
Dec 06 2007
On Thu, 06 Dec 2007 21:44:09 -0500, sambeau wrote:Bill Baxter Wrote:You've mentioned this already, but D's already got too many keywords. I think enum/macro is fine if it's explained in the docs. Let's not add more keywords, esp. for minimal net benefit.Paul Anderson wrote:how about replacing 'enum' with 'def' def X { A, B, C } def { A, B = 5+7, C, D = 8, E } def int A = 0; def int B = 1; def int C = 2; def x = 3; def long y = 4; Then we aren't changing the implementation, just the semantics so that they fit the implementation better. ... thoughts?Walter Bright Wrote:That's not bad either. final, alias, macro -- they all make more sense than reusing 'enum' for manifest constants that aren't really enumerating anything. --bbThat leaves what to do about manifest constants. It occurs that we already have a mechanism for them - enums. So why not: enum x = 3; enum long y = 4; ? I think that solves our problem. There's one last problem: class C { } const(C)[] a; a[3] = new C(); // error, x[3] is const does not work with this new regime. Every twist we tried to make it work caused other problems. Eventually, it just became clear that this just is not going to work. But, the following does work: a ~= new C(); a = a[1..3]; a = b; just like for strings. One can copy, concatenate, and slice such arrays (just like for strings). It's not so bad. Andrei also mentioned the possibility of using a template: TailConst!(C)[] a; which would do whatever was necessary under the hood to allow the elements of a to be rebound while still keeping the contents of the C objects const.I don't care for 'enum' used in this way. It distracts from (dilutes?) the meaning as an enumerated type. How about final? final x = 3; final real y = 7.5; 'final' is already a keyword and it's already used to declare one flavor of const in Java. Paul
Dec 07 2007
Denton Cockburn Wrote:You've mentioned this already, but D's already got too many keywords. I think enum/macro is fine if it's explained in the docs. Let's not add more keywords, esp. for minimal net benefit.Having specific, obvious keywords for different concepts may cause less confusion than selecting a loosely related keyword from the existing pool based on a best match approach. But then again I am not the one who pays for implementing it so it's easy to say.
Dec 07 2007
On Fri, 07 Dec 2007 04:14:39 -0500, guslay wrote:Denton Cockburn Wrote:From the explanations of what enum actually does in D (which is different than C/C++ already), it actually makes a lot of sense. I figure D changes to the meaning of C/C++ keywords are already documented, so it's not a big deal to just add: and it also means... Why use new keywords to express concepts that are already explainable with current and documented keywords...You've mentioned this already, but D's already got too many keywords. I think enum/macro is fine if it's explained in the docs. Let's not add more keywords, esp. for minimal net benefit.Having specific, obvious keywords for different concepts may cause less confusion than selecting a loosely related keyword from the existing pool based on a best match approach. But then again I am not the one who pays for implementing it so it's easy to say.
Dec 07 2007
Walter Bright Wrote:Yes for that reason, and the other reason is one rarely wants storage allocated for manifest constants. windows.d has 10,000 declarations in it, who wants 40K of executable bloat from const declarations?const int x = 1; Doesn't x get substituted by 1 everywhere in a constant propagation pass? I thought it didn't take storage, at least in optimization mode.
Dec 06 2007
"guslay" <guslay gmail.com> wrote in message news:fjao2r$ii4$1 digitalmars.com...Walter Bright Wrote:all those Win32 constants actually adds over 50KB of bloat. Tango would up using enum instead, and pulled some silly linker stunts to eliminate the bloat. I think you can take the address of a const?Yes for that reason, and the other reason is one rarely wants storage allocated for manifest constants. windows.d has 10,000 declarations in it, who wants 40K of executable bloat from const declarations?const int x = 1; Doesn't x get substituted by 1 everywhere in a constant propagation pass? I thought it didn't take storage, at least in optimization mode.
Dec 06 2007
Kris Wrote:"guslay" <guslay gmail.com> wrote in message news:fjao2r$ii4$1 digitalmars.com...You're right, without whole program optimization it would probably only be optimized within the scope of a module.Walter Bright Wrote:all those Win32 constants actually adds over 50KB of bloat. Tango would up using enum instead, and pulled some silly linker stunts to eliminate the bloat. I think you can take the address of a const?Yes for that reason, and the other reason is one rarely wants storage allocated for manifest constants. windows.d has 10,000 declarations in it, who wants 40K of executable bloat from const declarations?const int x = 1; Doesn't x get substituted by 1 everywhere in a constant propagation pass? I thought it didn't take storage, at least in optimization mode.
Dec 06 2007
Kris wrote:"guslay" <guslay gmail.com> wrote in message news:fjao2r$ii4$1 digitalmars.com...No, you can't, but IIRC Walter said that was actually a bug. Currently they create bloat, but are inaccessable!Walter Bright Wrote:all those Win32 constants actually adds over 50KB of bloat. Tango would up using enum instead, and pulled some silly linker stunts to eliminate the bloat. I think you can take the address of a const?Yes for that reason, and the other reason is one rarely wants storage allocated for manifest constants. windows.d has 10,000 declarations in it, who wants 40K of executable bloat from const declarations?const int x = 1; Doesn't x get substituted by 1 everywhere in a constant propagation pass? I thought it didn't take storage, at least in optimization mode.
Dec 07 2007
Kris wrote:I think you can take the address of a const?Yes, which is one of the problems with using const to declare manifest constants. The other is the type of the constant will be 'const', which may not be desirable.
Dec 08 2007