digitalmars.D - PhobosWatch: manifest => enum
- Bill Baxter (8/8) Dec 27 2007 Timestamp:
- =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= (16/25) Dec 27 2007 -----BEGIN PGP SIGNED MESSAGE-----
- Walter Bright (5/6) Dec 28 2007 Yeah, I figure I'll get fricasseed over that one. The most compelling
- Hannibal Lector (16/23) Dec 28 2007 "Walter Fricassé"
- =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= (24/31) Dec 28 2007 -----BEGIN PGP SIGNED MESSAGE-----
- Walter Bright (10/28) Dec 28 2007 Not really, just loosened up the restrictions on enum. The
- Bruce Adams (15/24) Dec 28 2007 a =
- Walter Bright (7/24) Dec 28 2007 The issue stems from trying to decide if const(T) is always, or only
- Janice Caron (9/11) Dec 28 2007 I don't think anyone's arguing with that. We're just saying that the
- Walter Bright (7/22) Dec 28 2007 It isn't hard to make invariant(uint) implicitly convertible to uint, so...
- Sean Kelly (4/8) Dec 28 2007 The weird thing for me is that this will allow individual enums of any
- Sean Kelly (7/16) Dec 28 2007 err... make that unnamed and named. One could argue that support for
- Walter Bright (10/15) Dec 28 2007 Right. Anonymous enums are already conventionally used not to declare
- Bruce Adams (27/42) Dec 28 2007 =
- Walter Bright (5/15) Dec 28 2007 Doesn't "static const" strike you has a hack? It does to me. It has
- Bruce Adams (19/34) Dec 28 2007 Not really no. The enum hack is a hack because it is a way of making the...
- Sean Kelly (7/25) Dec 30 2007 Yup. I simply find it troublesome that /conventions/ in C/C++ are being...
- Bruce Adams (14/36) Dec 30 2007 se =
- Sean Kelly (5/9) Dec 30 2007 Yup. And I do. But many long-time C++ programmers still seem to use
- Walter Bright (10/12) Dec 28 2007 The following will work:
- Jason House (3/6) Dec 28 2007 ... so annonymous enums have no type for the enumeration as a whole, but
- Steven Schveighoffer (28/34) Dec 28 2007 This currently works:
- Walter Bright (7/20) Dec 28 2007 No change here, one and two are longs with values 0 and 1.
- Walter Bright (4/12) Dec 28 2007 Yes. This has always been possible:
- Jason House (6/8) Dec 28 2007 I really meant other than integral types. Â More accurately, however, I
- Derek Parnell (11/26) Dec 28 2007 Will your syntax allow declarations of single values? e.g.
- Leandro Lucarella (16/43) Dec 28 2007 With this example, I guess Walter will say:
- Walter Bright (2/6) Dec 28 2007 Yes.
- =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= (34/55) Dec 28 2007 -----BEGIN PGP SIGNED MESSAGE-----
- Steven Schveighoffer (6/21) Dec 28 2007 I agree with everything you are saying, except I think Walter is thinkin...
- Bruce Adams (34/61) Dec 28 2007 re =
- Janice Caron (29/53) Dec 28 2007 Oooh - I think I ought to say something here, since I was one of the
- Steven Schveighoffer (12/69) Dec 28 2007 I don't disagree with you :) I'm merely clarifying Walter's gripe.
- =?UTF-8?B?IkrDqXLDtG1lIE0uIEJlcmdlciI=?= (19/98) Dec 28 2007 -----BEGIN PGP SIGNED MESSAGE-----
- Bruce Adams (5/26) Dec 28 2007 Another possibility is you might want a way to assert that something mus...
- Walter Bright (10/20) Dec 28 2007 The problem with head const is that to make the concept work, you also
- Janice Caron (25/33) Dec 28 2007 It doesn't? For structs
- Steven Schveighoffer (8/18) Dec 28 2007 What about:
- Janice Caron (6/11) Dec 28 2007 Yeah, you're right.
- Steven Schveighoffer (4/18) Dec 28 2007 Is that valid? I didn't think dup could be a compile-time constant beca...
- Walter Bright (8/30) Dec 28 2007 Imagine you have:
- Oskar Linde (29/47) Jan 04 2008 *BEEP* Confusion warning: you mean *constant*, not "const". Huge
- Janice Caron (14/19) Jan 04 2008 I see a problem there. You said that a is template-like, and
- Oskar Linde (24/35) Jan 04 2008 a is a constant known at compile time. It doesn't need to be part of the...
- Sean Kelly (5/18) Jan 04 2008 Yup. This is what I don't like about the current design as well. What
- Jason House (3/21) Jan 04 2008 I looked his proposal up earlier today. It's at http://www.csc.kth.se/~...
- Bruno Medeiros (9/23) Jan 05 2008 One wouldn't, because that does not make sense. More exactly, it does
- =?UTF-8?B?IkrDqXLDtG1lIE0uIEJlcmdlciI=?= (45/71) Dec 28 2007 -----BEGIN PGP SIGNED MESSAGE-----
- Walter Bright (9/33) Dec 28 2007 This is where we start to see a problem if we don't type const(int)
- =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= (20/42) Dec 28 2007 -----BEGIN PGP SIGNED MESSAGE-----
- Janice Caron (8/10) Dec 28 2007 Manifest constants are invariant, so in practice it will be
- Walter Bright (3/8) Dec 28 2007 Since one cannot take the address of a manifest constant, the
- =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= (21/31) Dec 28 2007 -----BEGIN PGP SIGNED MESSAGE-----
- Walter Bright (3/9) Dec 28 2007 Yes, that could be done, but we're still stymied by the problem that we
- =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= (18/28) Dec 29 2007 -----BEGIN PGP SIGNED MESSAGE-----
- Walter Bright (6/13) Dec 29 2007 Consider the following:
- Bill Baxter (7/23) Dec 29 2007 Huh? So the fix is to make constants not const? Seems like the problem...
- Walter Bright (9/33) Dec 29 2007 We don't have to worry about rvalue literals not being const, because:
- =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= (27/43) Dec 29 2007 -----BEGIN PGP SIGNED MESSAGE-----
- Walter Bright (15/22) Dec 29 2007 I really did try to figure out how to make that work, but it just
- Janice Caron (12/19) Dec 29 2007 In full agreement with you, Walter, having understood all your points
- Walter Bright (2/4) Jan 02 2008 We could, but my thinking hasn't progressed that far.
- Janice Caron (8/19) Dec 29 2007 Actually, come to think of it, the implementation of MyInt.dup would hav...
- =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= (55/64) Dec 29 2007 -----BEGIN PGP SIGNED MESSAGE-----
- Janice Caron (15/19) Dec 30 2007 The word "auto" is redundant here.
- =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= (21/41) Dec 31 2007 -----BEGIN PGP SIGNED MESSAGE-----
- Christopher Wright (8/63) Dec 30 2007 That doesn't really make sense. You could push off const one level:
- =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= (31/94) Dec 30 2007 -----BEGIN PGP SIGNED MESSAGE-----
- Walter Bright (6/24) Jan 02 2008 I did think of doing that way, but:
- =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= (22/29) Jan 02 2008 -----BEGIN PGP SIGNED MESSAGE-----
- Bruno Medeiros (9/36) Jan 05 2008 That is a valid problem. But it is a problem with the const semantics
- Bruno Medeiros (5/41) Jan 05 2008 You mean head-most const (or just head const), not tail-most const.
- Frank Benoit (3/19) Dec 29 2007 Why is it neccessary to transfer the const for value types? The
- Walter Bright (2/4) Dec 29 2007 Very good question. I tried to answer it in my reply to Jerome.
- Derek Parnell (19/35) Dec 29 2007 I think I'm confused here. Are you saying Walter, that in this example, ...
- Walter Bright (4/37) Dec 29 2007 No, I'm saying it would be const(int), which is why we need a way to
- =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= (30/46) Dec 31 2007 -----BEGIN PGP SIGNED MESSAGE-----
- Bill Baxter (8/46) Dec 31 2007 Thanks for mentioning that. That's what I was thinking too. Walter
- Christopher Wright (21/55) Dec 31 2007 You basically want this to fail:
- Russell Lewis (12/28) Jan 02 2008 I'll ignore for the moment the (very tricky) problem of assigning copies...
- Janice Caron (17/27) Jan 02 2008 But typeof(i) /isn't/ int. typeof(i) is const(int). The problem is not
- Russell Lewis (3/16) Jan 02 2008 I was suggesting how things *should* be, not how they are. Sorry if I
- Russell Lewis (11/28) Jan 02 2008 Hmmm...maybe the problem isn't with auto, after all. Maybe what I'm
- Derek Parnell (16/22) Dec 28 2007 -----BEGIN PGP SIGNED MESSAGE-----
- Janice Caron (6/8) Dec 28 2007 No.
- Derek Parnell (11/16) Dec 28 2007 Why not?
- Walter Bright (4/9) Dec 28 2007 What happens is the compiler emits data to the object file whenever the
- Janice Caron (13/25) Dec 29 2007 I was going to answer this, but Walter got there first and answered it
- James Dennett (9/30) Dec 28 2007 Surely you don't want to make a language that's less clear
- Walter Bright (6/24) Dec 28 2007 No, but a simple, clean implementation can be an indication of a simple,...
- Bruno Medeiros (5/19) Jan 05 2008 It can indicate, but it's not a 100% guarantee of such!
- Lars Ivar Igesund (9/16) Dec 28 2007 And rightfully so. This is one of the worse decisions among the bad ones...
- John Reimer (14/29) Dec 28 2007 It'll do. I'd say it's bad, but not that bad (I think "manifest" looked...
- Lars Ivar Igesund (12/38) Dec 28 2007 Considering that none of the "established" bad decisions from 1.0 seems ...
- John Reimer (3/21) Dec 28 2007 True. Can't argue with that.
- Steven Schveighoffer (11/17) Dec 28 2007 Whether you use enum or manifest or some other keyword, you are already
- Walter Bright (3/7) Dec 28 2007 enum is already used to declare arbitrary constants *that do not have an...
- John Reimer (12/20) Dec 28 2007 And, several times this argument has been rebuffed:
- Steven Schveighoffer (14/21) Dec 28 2007 The implementation does not follow the semantics. An enum is still
- Walter Bright (11/15) Dec 28 2007 I understand your point, but also consider that adding yet a fourth way
- =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= (25/40) Dec 28 2007 -----BEGIN PGP SIGNED MESSAGE-----
- Janice Caron (7/9) Dec 28 2007 Actually, I think that's a fifth way. You may have forgotten about
- Hxal (5/20) Dec 28 2007 Except you need a specific set of compiler and linker options for that e...
- Steven Schveighoffer (37/51) Dec 28 2007 This is worse. You are now changing the meaning of enum as it was in C ...
- Walter Bright (7/16) Dec 28 2007 C, C++, and D already work that way. Such are in common use, and I've
- Steven Schveighoffer (13/29) Dec 28 2007 You missed the point of my example :) I'm not debating anonymous
- Walter Bright (15/29) Dec 28 2007 It doesn't mean you shouldn't, either. This goes on all the time in
- James Dennett (10/24) Dec 28 2007 No, they don't. In C, x has integral type, whether the enum is
- Walter Bright (2/3) Dec 28 2007 You're right, I should have gone back and checked the spec.
- Derek Parnell (6/27) Dec 28 2007 So in short, 'enum' no longer stands for 'enumeration'.
- Don Clugston (26/33) Dec 28 2007 This statement really disturbs me, as this is clearly a major change to ...
- Janice Caron (4/6) Dec 29 2007 Even more interestingly, what about
- Walter Bright (3/13) Dec 29 2007 It would give the same result as:
-
Bruce Adams
(23/31)
Dec 29 2007
On Sat, 29 Dec 2007 08:36:07 -0000, Janice Caron
- Bruce Adams (17/31) Dec 29 2007 =
- Walter Bright (49/95) Dec 29 2007 None of the enhancements impair this.
- BLS (3/3) Dec 29 2007 Why not keeping enum as it was and use manfifest as enhanced enum ?
- Walter Bright (3/5) Dec 29 2007 Because, then there's a fourth way to declare constants. 3 seems to be
- =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= (19/25) Dec 29 2007 -----BEGIN PGP SIGNED MESSAGE-----
- John Reimer (33/39) Dec 29 2007 I think the distinction comes down to adding another keyword, not a
- Walter Bright (20/46) Dec 29 2007 The previous problems we were having with the design of the const system...
- John Reimer (12/53) Dec 29 2007 LOL! That's a good analogy... :) Although, there's probably an equally...
- Lars Ivar Igesund (10/14) Dec 30 2007 Of course we will, but it is yet another feature that will build annoyan...
- BLS (6/12) Dec 30 2007 In case that you can use a keyword in 4 different ways this will
- Bruce Adams (60/83) Dec 29 2007 s =
- Janice Caron (14/15) Dec 29 2007 There is no opIncrement().
- Walter Bright (6/64) Dec 29 2007 opIncrement is redundant, as it's a subset of opAdd.
- Bruce Adams (57/99) Dec 29 2007 No problem there then.
- Janice Caron (16/20) Dec 29 2007 In a true enumeration, it isn't that unreasonable to equate ++ or +1
-
Bruce Adams
(15/36)
Dec 29 2007
On Sun, 30 Dec 2007 03:41:40 -0000, Janice Caron
- James Dennett (8/25) Dec 29 2007 Except if you care about efficiency, in which case you might
- =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= (31/46) Dec 29 2007 -----BEGIN PGP SIGNED MESSAGE-----
- Janice Caron (19/24) Dec 29 2007 It would be /really/ cool if Walter just implemented everything as he
- Bastiaan Veelo (6/34) Dec 29 2007 "manifest", if not "define" (my preference) or "pure".
- Steven Schveighoffer (4/21) Dec 29 2007 Correct me if I'm wrong, but isn't opAdd disallowed at compile time beca...
- Walter Bright (3/5) Dec 29 2007 You're quite right. But I do intend to eventually extend CTFE to get
- Bastiaan Veelo (8/23) Dec 30 2007 You can regard me as a newcomer. In my view, enums are often used in
- Janice Caron (5/7) Dec 30 2007 You can't switch on an anonymous enum. Anonymous enums have no type,
- Derek Parnell (26/35) Dec 30 2007 And yet this compiles and runs ...
- 0ffh (9/23) Dec 30 2007 And I'd have been surprised if not... if it was called
- Bastiaan Veelo (7/44) Dec 30 2007 Yes, and although the extended enum would allow three to be defined as
- Walter Bright (2/36) Dec 30 2007 Yes, and x is of type int, not anonymous enum.
- Janice Caron (5/9) Dec 30 2007 OK, so everyone pointed out I got that wrong. Thanks, guys.
- 0ffh (22/24) Dec 30 2007 with
- 0ffh (3/9) Dec 30 2007 Ooops, I suppose there should be commas here not semicolons...
- Frits van Bommel (11/14) Dec 30 2007 Actually, D also allows string switch. However, I'm pretty sure you
- 0ffh (4/11) Dec 30 2007 Hmmm, that's rather... cool. :)
- Janice Caron (20/29) Dec 30 2007 This bit of conversation seems to have lost track of the original
- Bastiaan Veelo (4/41) Dec 30 2007 Thank you for reminding me of the proper way of switching on enums. And
- Walter Bright (4/9) Dec 30 2007 The heterogeneous types for enums would only be for anonymous enums. I
- Sascha Katzner (10/14) Dec 30 2007 Now I'm confused. I thought an anonymous enum was an enum without a
- Walter Bright (11/26) Dec 30 2007 I meant that:
- Jarrod (16/24) Jan 02 2008 I hate to jump in so late to this already very discussed issue, but I'm
- Derek Parnell (6/16) Dec 28 2007 I'm reminded of a Coca-Cola bottle falling from the sky.
- John Reimer (4/19) Dec 28 2007 And we represent all the pygmies sitting in a circle, glumly looking at
- Dawid =?UTF-8?B?Q2nEmcW8YXJraWV3aWN6?= (2/3) Dec 28 2007 Good work. I may be in minority, but I think this is a good choice.
- guslay (3/13) Dec 28 2007 My only concern with enum is, will people use it?
- Pedro Ferreira (3/37) Dec 28 2007 It's here somewhere in this thread already.
- 0ffh (2/2) Dec 29 2007 Okay, just let's reintroduce #define! [duck=]
- Bruce Adams (5/7) Dec 29 2007 The way mixin's can be abused 'we' kind of have already [crawls into hid...
- John Reimer (5/9) Dec 29 2007 Heh, it seems that might be the only way to avoid addition of a new
- Bruce Adams (3/11) Dec 29 2007 Never a grassy knoll around when you need one.
Timestamp: 12/27/07 20:47:21 (5 hours ago) Author: walter Message: manifest => enum http://www.dsource.org/projects/phobos/changeset/536 --bb
Dec 27 2007
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Bill Baxter wrote:Timestamp: 12/27/07 20:47:21 (5 hours ago) Author: walter Message: manifest => enum http://www.dsource.org/projects/phobos/changeset/536:( Jerome - -- +------------------------- Jerome M. BERGER ---------------------+ | mailto:jeberger free.fr | ICQ: 238062172 | | http://jeberger.free.fr/ | Jabber: jeberger jabber.fr | +---------------------------------+------------------------------+ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) iD8DBQFHdKTVd0kWM4JG3k8RAvnWAJ9t+pKVObDUmUdJynxKdp3+A3f5gQCfa2tK FQqMoW9i0nPhmzIQpN18E7o= =c0ln -----END PGP SIGNATURE-----
Dec 27 2007
Jérôme M. Berger wrote::(Yeah, I figure I'll get fricasseed over that one. The most compelling argument is that we already have 3 ways to declare a constant, adding a fourth gets very difficult to justify. As opposed to a minor extension to enums.
Dec 28 2007
Walter Bright Wrote:Jérôme M. Berger wrote:"Walter Fricassé" Ingredients (serve six): 3 tablespoons oil, 2 big onions, sliced fine, 1 kg Walter (cut into pieces), Salt & pepper, 3 chopped tomatoes, Thyme & chopped parsley, 1/2 teaspoon ginger/garlic mixture. Method: Heat oil and fry onion until transparent. Add pieces of Walter, season with salt and pepper. Stir-fry until pieces of Walter are lightly brown. Add tomatoes, thyme, chopped parsley and ginger/garlic mixture. Sprinkle over a little more salt and some water (half cup). Mix, cover and cook until Walter is tender and curry, dry. Serve with rice,lentil soup and chutneys.:(Yeah, I figure I'll get fricasseed over that one. The most compelling argument is that we already have 3 ways to declare a constant, adding a fourth gets very difficult to justify. As opposed to a minor extension to enums.
Dec 28 2007
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Walter Bright wrote:Jérôme M. Berger wrote:This is an artificial distinction: you *are* adding a fourth way to declare a constant, the only question is what syntax to use: either a counter-intuitive extension to enums or a new keyword (or a minor extension to the alias keyword as was suggested by somebody). BTW, I think it was Janice who suggested that the compiler should know whether a constant needs to be manifest or not (depending on whether its address is taken somewhere). This would remove the need for a way to distinguish manifest constants explicitly. Any thoughts on that? Jerome - -- +------------------------- Jerome M. BERGER ---------------------+ | mailto:jeberger free.fr | ICQ: 238062172 | | http://jeberger.free.fr/ | Jabber: jeberger jabber.fr | +---------------------------------+------------------------------+ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) iD8DBQFHdNVCd0kWM4JG3k8RAu1kAJ97kgXJW4tIcb0ZQYPHNHjmFe+JiwCggGuI GIlw7vHFlXSNCFo5qI1pSYA= =FcvO -----END PGP SIGNATURE-----:(Yeah, I figure I'll get fricasseed over that one. The most compelling argument is that we already have 3 ways to declare a constant, adding a fourth gets very difficult to justify. As opposed to a minor extension to enums.
Dec 28 2007
Jérôme M. Berger wrote:Walter Bright wrote:Not really, just loosened up the restrictions on enum. The implementation code is actually simpler <g>.Jérôme M. Berger wrote:This is an artificial distinction: you *are* adding a fourth way to declare a constant,:(Yeah, I figure I'll get fricasseed over that one. The most compelling argument is that we already have 3 ways to declare a constant, adding a fourth gets very difficult to justify. As opposed to a minor extension to enums.the only question is what syntax to use: either a counter-intuitive extension to enums or a new keyword (or a minor extension to the alias keyword as was suggested by somebody).I found the "use an alias when declaring one constant" and "use an enum when declaring more than one constant" to be difficult to justify. It's like saying arrays with only one element should not be allowed.BTW, I think it was Janice who suggested that the compiler should know whether a constant needs to be manifest or not (depending on whether its address is taken somewhere). This would remove the need for a way to distinguish manifest constants explicitly. Any thoughts on that?The reason this won't work is because: const int x = 3; will type x as const(int), not int. There needs to be a way to declare a constant of type int.
Dec 28 2007
On Fri, 28 Dec 2007 11:15:08 -0000, Walter Bright = <newshound1 digitalmars.com> wrote:a =BTW, I think it was Janice who suggested that the compiler should know whether a constant needs to be manifest or not (depending on whether its address is taken somewhere). This would remove the need for a way to distinguish manifest constants explicitly. Any thoughts on that?The reason this won't work is because: const int x =3D 3; will type x as const(int), not int. There needs to be a way to declare=constant of type int.This doesn't make sense to me. Why would you ever want a constant that w= as = not const? and particularly a manifest constant? The only way you can change a = manifest constant is by changing the source code. Things don't come much more constant than = that. The only conceivable reason I can think of is that there is a bug or = misfeature somewhere where something needs to be type equal when in fact it needs only to be = = type compatible.
Dec 28 2007
Bruce Adams wrote:On Fri, 28 Dec 2007 11:15:08 -0000, Walter Bright <newshound1 digitalmars.com> wrote:The issue stems from trying to decide if const(T) is always, or only sometimes, a different type than T. It must be a different type if T is a struct or class type. Pulling on the string of trying to make the type system completely consistent (so that generic code will work), and on the idea that a struct can be used to wrap any type, and one is drawn inevitably to conclude that const(T) is always a different type from T.The reason this won't work is because: const int x = 3; will type x as const(int), not int. There needs to be a way to declare a constant of type int.This doesn't make sense to me. Why would you ever want a constant that was not const? and particularly a manifest constant? The only way you can change a manifest constant is by changing the source code. Things don't come much more constant than that. The only conceivable reason I can think of is that there is a bug or misfeature somewhere where something needs to be type equal when in fact it needs only to be type compatible.
Dec 28 2007
On 12/28/07, Walter Bright <newshound1 digitalmars.com> wrote:and one is drawn inevitably to conclude that const(T) is always a different type from T.I don't think anyone's arguing with that. We're just saying that the behavior of auto x = could be tweaked to drop the head constancy. It's the same with passing things to functions. void f(int x) { /*...*/ } f(DAYS_IN_WEEK); we want this to compile, right? Even though DAYS_IN_WEEK is likely to have type invariant(uint). You should always be allowed to create a mutable copy (though which preserves tail constancy).
Dec 28 2007
Janice Caron wrote:On 12/28/07, Walter Bright <newshound1 digitalmars.com> wrote:Yes, but then other things break.and one is drawn inevitably to conclude that const(T) is always a different type from T.I don't think anyone's arguing with that. We're just saying that the behavior of auto x = could be tweaked to drop the head constancy.It's the same with passing things to functions. void f(int x) { /*...*/ } f(DAYS_IN_WEEK); we want this to compile, right? Even though DAYS_IN_WEEK is likely to have type invariant(uint).It isn't hard to make invariant(uint) implicitly convertible to uint, so that can work.You should always be allowed to create a mutable copy (though which preserves tail constancy).There is no way to do this - unless you can come up with a way to declare tail const member functions in a reasonable way. I failed to solved this problem.
Dec 28 2007
Walter Bright wrote:I found the "use an alias when declaring one constant" and "use an enum when declaring more than one constant" to be difficult to justify. It's like saying arrays with only one element should not be allowed.The weird thing for me is that this will allow individual enums of any type but grouped enums of only numeric types. Sean
Dec 28 2007
Sean Kelly wrote:Walter Bright wrote:err... make that unnamed and named. One could argue that support for unnamed enums is simply for ease of porting from C rather than because it's a feature that really makes sense in a new language. So making it even more entrenched is undesirable. But we need the feature and if "enum" is it then... SeanI found the "use an alias when declaring one constant" and "use an enum when declaring more than one constant" to be difficult to justify. It's like saying arrays with only one element should not be allowed.The weird thing for me is that this will allow individual enums of any type but grouped enums of only numeric types.
Dec 28 2007
Sean Kelly wrote:err... make that unnamed and named. One could argue that support for unnamed enums is simply for ease of porting from C rather than because it's a feature that really makes sense in a new language. So making it even more entrenched is undesirable. But we need the feature and if "enum" is it then...Right. Anonymous enums are already conventionally used not to declare enums, but a bunch of (not necessarily related) manifest constants. In fact, in C++ we see: template<> class factorial<1> { public: enum { result = 1 }; }; where anonymous enums are clearly used to declare manifest constants.
Dec 28 2007
On Fri, 28 Dec 2007 18:43:38 -0000, Walter Bright = <newshound1 digitalmars.com> wrote:Sean Kelly wrote:=err... make that unnamed and named. One could argue that support for=e =unnamed enums is simply for ease of porting from C rather than becaus=it =it's a feature that really makes sense in a new language. So making ==even more entrenched is undesirable. But we need the feature and if =="enum" is it then...Right. Anonymous enums are already conventionally used not to declare =enums, but a bunch of (not necessarily related) manifest constants. In==fact, in C++ we see: template<> class factorial<1> { public: enum { result =3D 1 }; }; where anonymous enums are clearly used to declare manifest constants.That looks similar to the workaround for old compilers which didn't = support static consts. template<> class factorial<1> { public: static const int result =3D 1; }; I can see the desire for manifest constants here. You particularly don't= = want to bloat your code with each intermediate value in a compile time computed expression. I've just tried an experiment on gcc (cygming 3.4.4). Compiled objects a= re = the same size whether enum or static const is used in a factorial template. I see this as = evidence that the enum hack is still just that, a hack to workaround dodgey compilers. So you are = propagating a hack into D if the C++ example is one of your primary reasons.
Dec 28 2007
Bruce Adams wrote:I can see the desire for manifest constants here. You particularly don't want to bloat your code with each intermediate value in a compile time computed expression. I've just tried an experiment on gcc (cygming 3.4.4). Compiled objects are the same size whether enum or static const is used in a factorial template. I see this as evidence that the enum hack is still just that, a hack to workaround dodgey compilers. So you are propagating a hack into D if the C++ example is one of your primary reasons.Doesn't "static const" strike you has a hack? It does to me. It has unique properties that are not deducible from the meaning of static or const by themselves. "const" is also a hack in C++, as "const int" sometimes means "const int" and sometimes just "int".
Dec 28 2007
On Fri, 28 Dec 2007 21:32:49 -0000, Walter Bright <newshound1 digitalmars.com> wrote:Bruce Adams wrote:Not really no. The enum hack is a hack because it is a way of making the compiler do something that was not possible in older versions of the language. static const is not a hack in that sense because it is an endorsed part of the C++ standard. The meaning of static const makes perfect sense from the meanings of static and const in C++. static meaning - belonging to the class (actually the current scope) rather than an instance of the class and const meaning a compile time constant. const can of course mean a read-only view in C++ as well which leads to other confusions and contortions. Personally I find the static meaning "compile time" in D a little surprising and not at all related to any of its C++ meanings.I can see the desire for manifest constants here. You particularly don't want to bloat your code with each intermediate value in a compile time computed expression. I've just tried an experiment on gcc (cygming 3.4.4). Compiled objects are the same size whether enum or static const is used in a factorial template. I see this as evidence that the enum hack is still just that, a hack to workaround dodgey compilers. So you are propagating a hack into D if the C++ example is one of your primary reasons.Doesn't "static const" strike you has a hack? It does to me. It has unique properties that are not deducible from the meaning of static or const by themselves. "const" is also a hack in C++, as "const int" sometimes means "const int" and sometimes just "int".
Dec 28 2007
Walter Bright wrote:Sean Kelly wrote:Yup. I simply find it troublesome that /conventions/ in C/C++ are being used as justification for new language features in D. For programmers new to D who do not have a C/C++ background, I'm not sure I'd want to resort to a history lesson when asked why 'enum', which is short for 'enumeration' is used to signify manifest constants. Seanerr... make that unnamed and named. One could argue that support for unnamed enums is simply for ease of porting from C rather than because it's a feature that really makes sense in a new language. So making it even more entrenched is undesirable. But we need the feature and if "enum" is it then...Right. Anonymous enums are already conventionally used not to declare enums, but a bunch of (not necessarily related) manifest constants. In fact, in C++ we see: template<> class factorial<1> { public: enum { result = 1 }; }; where anonymous enums are clearly used to declare manifest constants.
Dec 30 2007
On Mon, 31 Dec 2007 00:18:19 -0000, Sean Kelly <sean f4.ca> wrote:Walter Bright wrote:r =Sean Kelly wrote:err... make that unnamed and named. One could argue that support fo=se =unnamed enums is simply for ease of porting from C rather than becau==it's a feature that really makes sense in a new language. So making==it even more entrenched is undesirable. But we need the feature and=e =if "enum" is it then...Right. Anonymous enums are already conventionally used not to declar=n =enums, but a bunch of (not necessarily related) manifest constants. I=.fact, in C++ we see: template<> class factorial<1> { public: enum { result =3D 1 }; }; where anonymous enums are clearly used to declare manifest constants=Yup. I simply find it troublesome that /conventions/ in C/C++ are bei=ng =used as justification for new language features in D. For programmers==new to D who do not have a C/C++ background, I'm not sure I'd want to ==resort to a history lesson when asked why 'enum', which is short for ='enumeration' is used to signify manifest constants. SeanAs I've tried to point out before. Its not a 'convention' is a hack from= yesteryear. If you have a C++ compiler newer than 6 years old you should= use static const instead of enum for this.
Dec 30 2007
Bruce Adams wrote:As I've tried to point out before. Its not a 'convention' is a hack from yesteryear. If you have a C++ compiler newer than 6 years old you should use static const instead of enum for this.Yup. And I do. But many long-time C++ programmers still seem to use 'enum' out of habit. What ever happened to Don's suggestion of using 'pure' for this anyway? Sean
Dec 30 2007
Sean Kelly wrote:The weird thing for me is that this will allow individual enums of any type but grouped enums of only numeric types.The following will work: enum { x = 3, // x is int y = 4L, // y is long } The idea is that for anonymous enums, there is no type for the enumeration as a whole. Therefore, each member of the enumeration can have a different type.
Dec 28 2007
Walter Bright wrote:The idea is that for anonymous enums, there is no type for the enumeration as a whole. Therefore, each member of the enumeration can have a different type.... so annonymous enums have no type for the enumeration as a whole, but named enums will? Can named enums have a type other than int?
Dec 28 2007
"Jason House" wroteWalter Bright wrote:This currently works: enum X : long { one = 1L, two = 2L } This also currently works: enum : long { one = 1L, two = 2L } Enums can currently be based on any integral type. That brings up a couple of questions. Under the new regime, what happens with this code: enum {one, two} enum : long {one, two} enum : float {one, two} enum { float one = 1.0, two } and will enums in curly braces that are manifest constants have to be specified with semicolons or commas? ??? -SteveThe idea is that for anonymous enums, there is no type for the enumeration as a whole. Therefore, each member of the enumeration can have a different type.... so annonymous enums have no type for the enumeration as a whole, but named enums will? Can named enums have a type other than int?
Dec 28 2007
Steven Schveighoffer wrote:That brings up a couple of questions. Under the new regime, what happens with this code: enum {one, two}No change here, one and two are ints with values 0 and 1.enum : long {one, two}No change here, one and two are longs with values 0 and 1.enum : float {one, two}Change here, floats are now allowed as the base type, one and two are floats with values 0.0f and 1.0f.enum { float one = 1.0, two }Change here, one is float of value 1.0f, two is float of value 2.0f.and will enums in curly braces that are manifest constants have to be specified with semicolons or commas?commas.
Dec 28 2007
Jason House wrote:Walter Bright wrote:Yes. That is the way enums already work.The idea is that for anonymous enums, there is no type for the enumeration as a whole. Therefore, each member of the enumeration can have a different type.... so annonymous enums have no type for the enumeration as a whole, but named enums will?Can named enums have a type other than int?Yes. This has always been possible: enum Foo : long { X, Y }
Dec 28 2007
Jason House wrote:... so annonymous enums have no type for the enumeration as a whole, but named enums will? Can named enums have a type other than int?I really meant other than integral types. Â More accurately, however, I should have asked if named enums can contain as diverse a set of types as unnamed enums. I'm not sure what can be a manifest constant... Â int, long, float, string, struct, etc...
Dec 28 2007
On Fri, 28 Dec 2007 10:35:38 -0800, Walter Bright wrote:Sean Kelly wrote:Will your syntax allow declarations of single values? e.g. enum x = 3; enum y = 4L; Or will we have to use the {} form? enum {x = 3} enum {y = 4L} -- Derek Parnell Melbourne, Australia skype: derek.j.parnellThe weird thing for me is that this will allow individual enums of any type but grouped enums of only numeric types.The following will work: enum { x = 3, // x is int y = 4L, // y is long } The idea is that for anonymous enums, there is no type for the enumeration as a whole. Therefore, each member of the enumeration can have a different type.
Dec 28 2007
Derek Parnell, el 29 de diciembre a las 08:43 me escribiste:On Fri, 28 Dec 2007 10:35:38 -0800, Walter Bright wrote:With this example, I guess Walter will say: enum { x = 3, y = 4L } =) But the original question still remains, will be enum x = 3; supported? -- Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/ ---------------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------------- You can do better than me. You could throw a dart out the window and hit someone better than me. I'm no good! -- George ConstanzaSean Kelly wrote:Will your syntax allow declarations of single values? e.g. enum x = 3; enum y = 4L; Or will we have to use the {} form? enum {x = 3} enum {y = 4L}The weird thing for me is that this will allow individual enums of any type but grouped enums of only numeric types.The following will work: enum { x = 3, // x is int y = 4L, // y is long } The idea is that for anonymous enums, there is no type for the enumeration as a whole. Therefore, each member of the enumeration can have a different type.
Dec 28 2007
Derek Parnell wrote:Will your syntax allow declarations of single values? e.g. enum x = 3; enum y = 4L;Yes.
Dec 28 2007
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Walter Bright wrote:Jérôme M. Berger wrote:I don't think anybody suggested using an enum for declaring more than one constant. The suggestions were more on the line of: keyword { int x = 42; float y = 42.42; } Where "keyword" could be one of "constant", "invariant", "alias" or anything that means constant (but not "enum", anymore than "abstract" or "cat": those mean something else).Walter Bright wrote:the only question is what syntax to use: either a counter-intuitive extension to enums or a new keyword (or a minor extension to the alias keyword as was suggested by somebody).I found the "use an alias when declaring one constant" and "use an enum when declaring more than one constant" to be difficult to justify. It's like saying arrays with only one element should not be allowed.Er, why? Taking "&x" should return a "const (int)*" and using "x" directly should always work so long as you don't modify it. Are you telling us that the following code will fail: void func (int param) { } const int x = 42; int y = x; // <= This should work func (x); // <= This should work too Or is there something I'm missing here? Jerome - -- +------------------------- Jerome M. BERGER ---------------------+ | mailto:jeberger free.fr | ICQ: 238062172 | | http://jeberger.free.fr/ | Jabber: jeberger jabber.fr | +---------------------------------+------------------------------+ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) iD8DBQFHdQ18d0kWM4JG3k8RAmsFAKCoFDdLY69rxxKh/ByoRR+eKKHtVACfb2lK u2sdS/cU51nKadzhMs1burc= =hxW2 -----END PGP SIGNATURE-----BTW, I think it was Janice who suggested that the compiler should know whether a constant needs to be manifest or not (depending on whether its address is taken somewhere). This would remove the need for a way to distinguish manifest constants explicitly. Any thoughts on that?The reason this won't work is because: const int x = 3; will type x as const(int), not int. There needs to be a way to declare a constant of type int.
Dec 28 2007
""Jérôme M. Berger"" wroteWalter Bright wrote:I agree with everything you are saying, except I think Walter is thinking of the case: const int x; auto y = x; // y is now const -SteveThe reason this won't work is because: const int x = 3; will type x as const(int), not int. There needs to be a way to declare a constant of type int.Er, why? Taking "&x" should return a "const (int)*" and using "x" directly should always work so long as you don't modify it. Are you telling us that the following code will fail: void func (int param) { } const int x = 42; int y = x; // <= This should work func (x); // <= This should work too Or is there something I'm missing here?
Dec 28 2007
On Fri, 28 Dec 2007 14:55:48 -0000, Steven Schveighoffer = <schveiguy yahoo.com> wrote:""J=E9r=F4me M. Berger"" wrotere =Walter Bright wrote:The reason this won't work is because: const int x =3D 3; will type x as const(int), not int. There needs to be a way to decla=I agree with everything you are saying, except I think Walter is =a constant of type int.Er, why? Taking "&x" should return a "const (int)*" and using "x" directly should always work so long as you don't modify it. Are you telling us that the following code will fail: void func (int param) { } const int x =3D 42; int y =3D x; // <=3D This should work func (x); // <=3D This should work too Or is there something I'm missing here?thinking of the case: const int x; auto y =3D x; // y is now const -SteveThat would seem to be a 'problem' with auto. Should auto inherit constne= ss or not? i.e. const int x =3D 5; auto y =3D x; y =3D 4; // legal or breaking const correctness? The spec should say either: 1. auto always inherits constness (y is const) 2a. auto always throws away constness (y is not const) 2b. auto assigns the type but leaves const qualification to the user. i.e. const auto y =3D x; and auto y =3D x; are two different declarations one const one not regardless of x. Which is it now? and which makes most sense? I'm not sure I like 1 as a typical usage might be to create a temporary = = for something that is const and thus cannot be used directly. That said if x was a pointer = = rather than a POD type it must absolutely inherit the constness so for constistency it must be = 1. Although, I can't help thinking that values and pointers/references can = = have different behaviour because they are semantically quite different beasts. Regards, Bruce.
Dec 28 2007
On 12/28/07, Steven Schveighoffer <schveiguy yahoo.com> wrote:""Jérôme M. Berger"" wroteOooh - I think I ought to say something here, since I was one of the folk arguing that const(T) and const T should be interchangable. The thing is, I just don't see the problem. Given code like: const int x; auto y = x; it should be possible to end up with x being a manifest constant, unless the address is taken by some other piece of code somewhere else. As I've mentioned before, x is not merely const, it's actually /invariant/, despite the const declaration, because there is no conceivable way for any piece of code anywhere in the program to change it, ever (...except by doing stuff which is undefined, obviously, but that doesn't count). And that's good, right? If the compiler is really smart, it might be able to treat is as invariant(int). If not, treating it as const(int) is harmless. But as for y... y is a /copy/ of x, and clearly it should be possible to make a copy of a const thing and have the copy be mutable. Head constness needs to be dropped here, exactly as it is dropped in template distinction in D2.008 (t!(int) is the same thing as t!(const(int)) unless special syntax is used). In fact, x is very much like a template, and could be implemented in a similar way - don't instantiate it (allocate it storage space in the ROM segment) unless it is referenced (its address is taken). I don't see why any of this isn't possible. Maybe that's because I'm dumb and I'm missing something obvious, but I'm baffled as to what it is. And if I /haven't/ missed anything, then we don't need a new keyword /at all/ - be it enum, manifest, or anything else.Walter Bright wrote:I agree with everything you are saying, except I think Walter is thinking of the case: const int x; auto y = x; // y is now constThe reason this won't work is because: const int x = 3; will type x as const(int), not int. There needs to be a way to declare a constant of type int.Er, why? Taking "&x" should return a "const (int)*" and using "x" directly should always work so long as you don't modify it. Are you telling us that the following code will fail: void func (int param) { } const int x = 42; int y = x; // <= This should work func (x); // <= This should work too Or is there something I'm missing here?
Dec 28 2007
"Janice Caron" wroteOn 12/28/07, Steven Schveighoffer wrote:I don't disagree with you :) I'm merely clarifying Walter's gripe. I think there may be a better reason why your idea wouldn't work, but I am not sure how the compiler is implemented, so I can't really say much. However, it might be a problem when you are defining constants in one module to be used in other modules. How does the compiler know that those constants won't have their address taken somewhere else? When the compiler creates the object file, it has to assume since the symbol is public, it can have its address taken, no? If you had a specific D linker, you could modify the linker to take this into account, but that is not the case today. -Steve""Jérôme M. Berger"" wroteOooh - I think I ought to say something here, since I was one of the folk arguing that const(T) and const T should be interchangable. The thing is, I just don't see the problem. Given code like: const int x; auto y = x; it should be possible to end up with x being a manifest constant, unless the address is taken by some other piece of code somewhere else. As I've mentioned before, x is not merely const, it's actually /invariant/, despite the const declaration, because there is no conceivable way for any piece of code anywhere in the program to change it, ever (...except by doing stuff which is undefined, obviously, but that doesn't count). And that's good, right? If the compiler is really smart, it might be able to treat is as invariant(int). If not, treating it as const(int) is harmless. But as for y... y is a /copy/ of x, and clearly it should be possible to make a copy of a const thing and have the copy be mutable. Head constness needs to be dropped here, exactly as it is dropped in template distinction in D2.008 (t!(int) is the same thing as t!(const(int)) unless special syntax is used). In fact, x is very much like a template, and could be implemented in a similar way - don't instantiate it (allocate it storage space in the ROM segment) unless it is referenced (its address is taken). I don't see why any of this isn't possible. Maybe that's because I'm dumb and I'm missing something obvious, but I'm baffled as to what it is. And if I /haven't/ missed anything, then we don't need a new keyword /at all/ - be it enum, manifest, or anything else.Walter Bright wrote:I agree with everything you are saying, except I think Walter is thinking of the case: const int x; auto y = x; // y is now constThe reason this won't work is because: const int x = 3; will type x as const(int), not int. There needs to be a way to declare a constant of type int.Er, why? Taking "&x" should return a "const (int)*" and using "x" directly should always work so long as you don't modify it. Are you telling us that the following code will fail: void func (int param) { } const int x = 42; int y = x; // <= This should work func (x); // <= This should work too Or is there something I'm missing here?
Dec 28 2007
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Steven Schveighoffer wrote:"Janice Caron" wroteYou do it the same way it is done for templates (and in particular for the associated type information data): you allocate it in each module that uses it, but you put it in a special section that tells the linker to merge duplicate definitions. Jerome - -- +------------------------- Jerome M. BERGER ---------------------+ | mailto:jeberger free.fr | ICQ: 238062172 | | http://jeberger.free.fr/ | Jabber: jeberger jabber.fr | +---------------------------------+------------------------------+ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) iD8DBQFHdV10d0kWM4JG3k8RArGnAKCZomZsyJjTDsxLiu8BkIgb6SdzewCff3bx Oi1ANAeonj5JW8M6JgbMcCs= =8FdR -----END PGP SIGNATURE-----On 12/28/07, Steven Schveighoffer wrote:I don't disagree with you :) I'm merely clarifying Walter's gripe. I think there may be a better reason why your idea wouldn't work, but I am not sure how the compiler is implemented, so I can't really say much. However, it might be a problem when you are defining constants in one module to be used in other modules. How does the compiler know that those constants won't have their address taken somewhere else? When the compiler creates the object file, it has to assume since the symbol is public, it can have its address taken, no? If you had a specific D linker, you could modify the linker to take this into account, but that is not the case today.""J�r�me M. Berger"" wroteOooh - I think I ought to say something here, since I was one of the folk arguing that const(T) and const T should be interchangable. The thing is, I just don't see the problem. Given code like: const int x; auto y = x; it should be possible to end up with x being a manifest constant, unless the address is taken by some other piece of code somewhere else. As I've mentioned before, x is not merely const, it's actually /invariant/, despite the const declaration, because there is no conceivable way for any piece of code anywhere in the program to change it, ever (...except by doing stuff which is undefined, obviously, but that doesn't count). And that's good, right? If the compiler is really smart, it might be able to treat is as invariant(int). If not, treating it as const(int) is harmless. But as for y... y is a /copy/ of x, and clearly it should be possible to make a copy of a const thing and have the copy be mutable. Head constness needs to be dropped here, exactly as it is dropped in template distinction in D2.008 (t!(int) is the same thing as t!(const(int)) unless special syntax is used). In fact, x is very much like a template, and could be implemented in a similar way - don't instantiate it (allocate it storage space in the ROM segment) unless it is referenced (its address is taken). I don't see why any of this isn't possible. Maybe that's because I'm dumb and I'm missing something obvious, but I'm baffled as to what it is. And if I /haven't/ missed anything, then we don't need a new keyword /at all/ - be it enum, manifest, or anything else.Walter Bright wrote:I agree with everything you are saying, except I think Walter is thinking of the case: const int x; auto y = x; // y is now constThe reason this won't work is because: const int x = 3; will type x as const(int), not int. There needs to be a way to declare a constant of type int.Er, why? Taking "&x" should return a "const (int)*" and using "x" directly should always work so long as you don't modify it. Are you telling us that the following code will fail: void func (int param) { } const int x = 42; int y = x; // <= This should work func (x); // <= This should work too Or is there something I'm missing here?
Dec 28 2007
On Fri, 28 Dec 2007 17:32:32 -0000, Steven Schveighoffer <schveiguy yahoo.com> wrote:"Janice Caron" wroteAnother possibility is you might want a way to assert that something must never use any storage. However, that seems a little bizzare.I don't see why any of this isn't possible. Maybe that's because I'm dumb and I'm missing something obvious, but I'm baffled as to what it is. And if I /haven't/ missed anything, then we don't need a new keyword /at all/ - be it enum, manifest, or anything else.I don't disagree with you :) I'm merely clarifying Walter's gripe. I think there may be a better reason why your idea wouldn't work, but I am not sure how the compiler is implemented, so I can't really say much. However, it might be a problem when you are defining constants in one module to be used in other modules. How does the compiler know that those constants won't have their address taken somewhere else? When the compiler creates the object file, it has to assume since the symbol is public, it can have its address taken, no? If you had a specific D linker, you could modify the linker to take this into account, but that is not the case today. -Steve
Dec 28 2007
Janice Caron wrote:y is a /copy/ of x, and clearly it should be possible to make a copy of a const thing and have the copy be mutable.That doesn't work for structs or classes.Head constness needs to be dropped here, exactly as it is dropped in template distinction in D2.008 (t!(int) is the same thing as t!(const(int)) unless special syntax is used).The problem with head const is that to make the concept work, you also need the concept of tail const, and you also need to be able to separately manipulate head & tail const. That's how D's first cut at const worked, and it was a disaster. Just for fun, how would we define a tail const member function?I don't see why any of this isn't possible. Maybe that's because I'm dumb and I'm missing something obvious, but I'm baffled as to what it is. And if I /haven't/ missed anything, then we don't need a new keyword /at all/ - be it enum, manifest, or anything else.Believe me, we've been down this road for a year, trying all kinds of things. It doesn't work. We can get tantalizingly close to closing the circle, but cannot quite get there.
Dec 28 2007
On 12/28/07, Walter Bright <newshound1 digitalmars.com> wrote:Janice Caron wrote:It doesn't? For structs struct S {} const S x; auto y = x; By my reckoning x has type invariant(S) (which you could treat as const(S) if you wanted), and y would have type S. And for classes class C {} const C x; auto y = x; ...You're right, it doesn't work for classes. But is that really a problem? Isn't class C {} enum { C x; } auto y = x; exactly the same problem?y is a /copy/ of x, and clearly it should be possible to make a copy of a const thing and have the copy be mutable.That doesn't work for structs or classes.Just for fun, how would we define a tail const member function?Yeah, I agreed, it wouldn't work for classes. Still don't see any problem for structs though. I guess you're going to remind me that structs and classes must behave the same though - in which case you'll win the argument! :-)Believe me, we've been down this road for a year, trying all kinds of things. It doesn't work. We can get tantalizingly close to closing the circle, but cannot quite get there.Hey ho. I guess we can live with enum then. But I still think you're going to have a problem with class C {} enum { C x; } auto y = x;
Dec 28 2007
"Janice Caron" wroteOn 12/28/07, Walter Bright <newshound1 digitalmars.com> wrote:What about: struct S { char[] str}; const S x = S("hello".dup); auto y = x; If y is not const, then y.str is not const, yet it points to the same data as x. -SteveJanice Caron wrote:It doesn't? For structs struct S {} const S x; auto y = x;y is a /copy/ of x, and clearly it should be possible to make a copy of a const thing and have the copy be mutable.That doesn't work for structs or classes.
Dec 28 2007
On 12/28/07, Steven Schveighoffer <schveiguy yahoo.com> wrote:struct S { char[] str}; const S x = S("hello".dup); auto y = x; If y is not const, then y.str is not const, yet it points to the same data as x.Yeah, you're right. But doesn't the same problem occur with enum { S x = S("hello".dup); } auto y = x; ?
Dec 28 2007
"Janice Caron" wroteOn 12/28/07, Steven Schveighoffer <schveiguy yahoo.com> wrote:Is that valid? I didn't think dup could be a compile-time constant because it uses the heap... -Stevestruct S { char[] str}; const S x = S("hello".dup); auto y = x; If y is not const, then y.str is not const, yet it points to the same data as x.Yeah, you're right. But doesn't the same problem occur with enum { S x = S("hello".dup); } auto y = x; ?
Dec 28 2007
Janice Caron wrote:On 12/28/07, Walter Bright <newshound1 digitalmars.com> wrote:Imagine you have: struct S { int* p; } Because const is transitive, const(S) implies that now p points to const. But if you strip off the const in the assignment, you've lost the const-ness of p, and now you have a gaping hole in the const-correctness.Janice Caron wrote:It doesn't? For structs struct S {} const S x; auto y = x;y is a /copy/ of x, and clearly it should be possible to make a copy of a const thing and have the copy be mutable.That doesn't work for structs or classes.Isn't class C {} enum { C x; } auto y = x; exactly the same problem?No, because y will be of type C and will have the value null.You'd need tail const member functions for structs, too.Just for fun, how would we define a tail const member function?Yeah, I agreed, it wouldn't work for classes. Still don't see any problem for structs though.
Dec 28 2007
Walter Bright wrote:Janice Caron wrote:*BEEP* Confusion warning: you mean *constant*, not "const". Huge difference. :)On 12/28/07, Walter Bright <newshound1 digitalmars.com> wrote:Janice Caron wrote:y is a /copy/ of x, and clearly it should be possible to make a copy of a const thing and have the copy be mutable.The problem with the current const in D is the lack of orthogonality. As far as I can see, those problems would be solved by my orthogonal const proposal posted earlier. Constant values (such as structs) are by their nature always implicitly convertible to mutable values (worst case: just make a copy). The problem with the current const iteration is that there is no way to separate the orthogonal concepts constness (as in constants) from read-only access of references. Also, as far as I can see (not very) there would also not be any need for a third type of constant (the manifest one). const int x = 5; could behave like a template and only be instantiated when the address of x is taken. The result would be a const design, equally powerful but without spoiling the beauty and simplicity of the D1.0 const. In D1.0, when something is *constant*, you simply declare it as const: struct T { const int a = 5; int b; } static assert(T.sizeof == int.sizeof); No need to stop and think. In D2.0 it seems like you have to go through: "Hmm, this value will never change. I will mark it as const.... no wait invariant... or maybe manifest constant using the enumeration hack?" -- OskarImagine you have: struct S { int* p; } Because const is transitive, const(S) implies that now p points to const. But if you strip off the const in the assignment, you've lost the const-ness of p, and now you have a gaping hole in the const-correctness.That doesn't work for structs or classes.It doesn't? For structs struct S {} const S x; auto y = x;
Jan 04 2008
On 1/4/08, Oskar Linde <oskar.lindeREM ovegmail.com> wrote:struct T { const int a = 5; int b; } static assert(T.sizeof == int.sizeof);I see a problem there. You said that a is template-like, and instantiated only if its address is taken. That means that T itself is template-like, because it contains a. But I don't see how it can be. That static assert cannot compile unless T.sizeof is known. T.sizeof may be different in different modules, since one module may take the address of a, and another may not. For example: // In another module import module_where_T_is_declared; T t; p = &t.a; static assert(T.sizeof != int.sizeof); I would imagine that would make life very difficult for things like struct copying.
Jan 04 2008
Janice Caron wrote:On 1/4/08, Oskar Linde <oskar.lindeREM ovegmail.com> wrote:a is a constant known at compile time. It doesn't need to be part of the run time struct representation. There are two types of constants. Those known at compile time and those whose values are computed at run time. D1 uses two different keywords for those (const / final) and D2.009 defines both using the same keyword (const). In D2.009: struct T { const int a = 5; const int b; int c; } T t; T.sizeof == 8 // a occupies no space &t.a -> error 5 is not a lvalue &t.b -> ok &t.c -> ok I'm not sure this behavior in D2.009 is intentional or not though. &t.a could become legal (the template-like idea) but all instances of T would share the same a. So: T x,y; &x.a == &y.a; &x.b != &y.b; -- Oskarstruct T { const int a = 5; int b; } static assert(T.sizeof == int.sizeof);I see a problem there. You said that a is template-like, and instantiated only if its address is taken. That means that T itself is template-like, because it contains a. But I don't see how it can be.
Jan 04 2008
Oskar Linde wrote:In D1.0, when something is *constant*, you simply declare it as const: struct T { const int a = 5; int b; } static assert(T.sizeof == int.sizeof); No need to stop and think. In D2.0 it seems like you have to go through: "Hmm, this value will never change. I will mark it as const.... no wait invariant... or maybe manifest constant using the enumeration hack?"Yup. This is what I don't like about the current design as well. What was your orthogonal const proposal again? I've lost it amid the flood of const posts. Sean
Jan 04 2008
Sean Kelly Wrote:Oskar Linde wrote:I looked his proposal up earlier today. It's at http://www.csc.kth.se/~ol/const.pdf I almost posted asking how D 2.009 "const" differs from his "in" and D 2.009 "invariant" differs from his "const". I thought I understood, but then I noticed him use "const in" and "const const(T)"...In D1.0, when something is *constant*, you simply declare it as const: struct T { const int a = 5; int b; } static assert(T.sizeof == int.sizeof); No need to stop and think. In D2.0 it seems like you have to go through: "Hmm, this value will never change. I will mark it as const.... no wait invariant... or maybe manifest constant using the enumeration hack?"Yup. This is what I don't like about the current design as well. What was your orthogonal const proposal again? I've lost it amid the flood of const posts.
Jan 04 2008
Walter Bright wrote:One wouldn't, because that does not make sense. More exactly, it does not make sense to change the 'this' implicit parameter(as in "this = foo"), so the "head" value of 'this' is always immutable. This means that in a member function, the 'this' parameter should always be either head const, or head+tail const, but never just tail const. Isn't it so? -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DHead constness needs to be dropped here, exactly as it is dropped in template distinction in D2.008 (t!(int) is the same thing as t!(const(int)) unless special syntax is used).The problem with head const is that to make the concept work, you also need the concept of tail const, and you also need to be able to separately manipulate head & tail const. That's how D's first cut at const worked, and it was a disaster. Just for fun, how would we define a tail const member function?
Jan 05 2008
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Steven Schveighoffer wrote:""J�r�me M. Berger"" wroteThis is a problem whether x is a manifest constant or not: for consistency with class/struct references and pointers, y should be const. This is due to the fact that it is impossible to define a mutable reference to a const class. So we have the following: const MyClass o = new MyClass(); auto y = o; // <= y must be of type const(MyClass) Which means that for consistency, the following should result in const definitions of y1...y3 too: enum { e = 42 } const int var = 42; auto y1 = var; auto y2 = e; auto y3 = 42; Since we work in the real world, we need to be pragmatic here. IMO all three of these should result in mutable variables, as well as the following: const (const (MyStruct)*) s = new MyStruct; auto y4 = s; // <= y4 should be const (MyStruct)* // ie mutable pointer to const data // if such a beast is allowed by the // language. And in that case, there's nothing that really prevents an object from being a mutable reference to a const instance. If the whole head const / tail const debate gets us a language in which we can't have a mutable pointer (or reference) to const data, then const-correctness means that y4 should be fully const (as well as "auto" object references), but even so y1...y3 should be mutable. However, this has nothing to to with having the compiler detect automatically if a const variable should be allocated or not. This should be possible whatever the choice for "auto" variables. Jerome - -- +------------------------- Jerome M. BERGER ---------------------+ | mailto:jeberger free.fr | ICQ: 238062172 | | http://jeberger.free.fr/ | Jabber: jeberger jabber.fr | +---------------------------------+------------------------------+ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) iD8DBQFHdVs9d0kWM4JG3k8RAo0XAKCRO0C37/t0N7H8p8Cj8Zt63GDE7wCglC5L wbRK7avBl1kwVSLU1Y9O5/0= =SXv/ -----END PGP SIGNATURE-----Walter Bright wrote:I agree with everything you are saying, except I think Walter is thinking of the case: const int x; auto y = x; // y is now constThe reason this won't work is because: const int x = 3; will type x as const(int), not int. There needs to be a way to declare a constant of type int.Er, why? Taking "&x" should return a "const (int)*" and using "x" directly should always work so long as you don't modify it. Are you telling us that the following code will fail: void func (int param) { } const int x = 42; int y = x; // <= This should work func (x); // <= This should work too Or is there something I'm missing here?
Dec 28 2007
Jérôme M. Berger wrote:This is where we start to see a problem if we don't type const(int) differently from int - we no longer have a straightforward rule of what the type of &x is. This may not seem consequential in trivial cases, but when you start having more complex generic code, things can get maddening. C++ tries to have it both ways, leading to startling complexity in the language definition, and a lot of intractable problems cropping up in metaprogramming.Er, why? Taking "&x" should return a "const (int)*" and using "x" directly should always work so long as you don't modify it.BTW, I think it was Janice who suggested that the compiler should know whether a constant needs to be manifest or not (depending on whether its address is taken somewhere). This would remove the need for a way to distinguish manifest constants explicitly. Any thoughts on that?The reason this won't work is because: const int x = 3; will type x as const(int), not int. There needs to be a way to declare a constant of type int.Are you telling us that the following code will fail: void func (int param) { } const int x = 42; int y = x; // <= This should work func (x); // <= This should work too Or is there something I'm missing here?These will both still work.
Dec 28 2007
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Walter Bright wrote:Jérôme M. Berger wrote:I agree that "const (int)" and "int" should be different types. What I don't really see is why manifest constant need to be "int" rather than "const (int)". After all, any attempt to use one as non-const will fail (or should) so there's no real reason that they can't be "const (int)", is there? Jerome - -- +------------------------- Jerome M. BERGER ---------------------+ | mailto:jeberger free.fr | ICQ: 238062172 | | http://jeberger.free.fr/ | Jabber: jeberger jabber.fr | +---------------------------------+------------------------------+ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) iD8DBQFHdVOgd0kWM4JG3k8RAoKRAJ0SeQvVUmcwputyeK6YImrMm4EiIACgrTjQ Mvv9xUyUjcG8CY5w+7u0+cc= =lJgZ -----END PGP SIGNATURE-----This is where we start to see a problem if we don't type const(int) differently from int - we no longer have a straightforward rule of what the type of &x is. This may not seem consequential in trivial cases, but when you start having more complex generic code, things can get maddening. C++ tries to have it both ways, leading to startling complexity in the language definition, and a lot of intractable problems cropping up in metaprogramming.Er, why? Taking "&x" should return a "const (int)*" and using "x" directly should always work so long as you don't modify it.BTW, I think it was Janice who suggested that the compiler should know whether a constant needs to be manifest or not (depending on whether its address is taken somewhere). This would remove the need for a way to distinguish manifest constants explicitly. Any thoughts on that?The reason this won't work is because: const int x = 3; will type x as const(int), not int. There needs to be a way to declare a constant of type int.
Dec 28 2007
On 12/28/07, "Jérôme M. Berger" <jeberger free.fr> wrote:What I don't really see is why manifest constant need to be "int" rather than "const (int)"Manifest constants are invariant, so in practice it will be invariant(int), even if not explicitly declared as such. For this reason, I would hope that the compiler should be able to realise that const int x = 1; creates an x which could be stored in ROM, and automagically types x as invariant(int). Because of implicit casting, this cannot possibly break anything.
Dec 28 2007
Jérôme M. Berger wrote:I agree that "const (int)" and "int" should be different types. What I don't really see is why manifest constant need to be "int" rather than "const (int)". After all, any attempt to use one as non-const will fail (or should) so there's no real reason that they can't be "const (int)", is there?Since one cannot take the address of a manifest constant, the requirement that it be immutable goes away, since it can never be an lvalue.
Dec 28 2007
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Walter Bright wrote:Jérôme M. Berger wrote:Right. Replace "const" by "invariant" in my comment and the main point still stands: couldn't the compiler determine automatically if we take the address of an invariant variable and allocate memory for it or not based on that? This would remove the need for a special keyword/syntax for manifest constants: just declare them as "invariant" and let the compiler do the work. Jerome - -- +------------------------- Jerome M. BERGER ---------------------+ | mailto:jeberger free.fr | ICQ: 238062172 | | http://jeberger.free.fr/ | Jabber: jeberger jabber.fr | +---------------------------------+------------------------------+ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) iD4DBQFHdWPKd0kWM4JG3k8RAk2kAJ9PDwO5TsX2Sg7pkkVnCGcZP/ty0ACUDgdQ 6Qvm9osRRpRIXQ001Xk2Xw== =92yB -----END PGP SIGNATURE-----I agree that "const (int)" and "int" should be different types. What I don't really see is why manifest constant need to be "int" rather than "const (int)". After all, any attempt to use one as non-const will fail (or should) so there's no real reason that they can't be "const (int)", is there?Since one cannot take the address of a manifest constant, the requirement that it be immutable goes away, since it can never be an lvalue.
Dec 28 2007
Jérôme M. Berger wrote:Right. Replace "const" by "invariant" in my comment and the main point still stands: couldn't the compiler determine automatically if we take the address of an invariant variable and allocate memory for it or not based on that? This would remove the need for a special keyword/syntax for manifest constants: just declare them as "invariant" and let the compiler do the work.Yes, that could be done, but we're still stymied by the problem that we are unable to declare a constant of type 'int', only 'const(int)'.
Dec 28 2007
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Walter Bright wrote:Jérôme M. Berger wrote:I don't see any situation in which we would need a constant of type "int" instead of "const (int)" or "invariant (int)". After all, if it is a *constant*, it should be either "const" or "invariant", no? Jerome - -- +------------------------- Jerome M. BERGER ---------------------+ | mailto:jeberger free.fr | ICQ: 238062172 | | http://jeberger.free.fr/ | Jabber: jeberger jabber.fr | +---------------------------------+------------------------------+ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) iD8DBQFHdlu5d0kWM4JG3k8RAuVHAKCAkmTyAamEpMXMbgAY3IipNrX6qgCdFJ7y Ron+xf58hS43KfbHPsZVq7I= =YEWL -----END PGP SIGNATURE-----Right. Replace "const" by "invariant" in my comment and the main point still stands: couldn't the compiler determine automatically if we take the address of an invariant variable and allocate memory for it or not based on that? This would remove the need for a special keyword/syntax for manifest constants: just declare them as "invariant" and let the compiler do the work.Yes, that could be done, but we're still stymied by the problem that we are unable to declare a constant of type 'int', only 'const(int)'.
Dec 29 2007
Jérôme M. Berger wrote:Walter Bright wrote:Consider the following: const int X = 3; auto i = X; i = 4; // error, i is const Essentially, it would make type inference far less useful.Yes, that could be done, but we're still stymied by the problem that we are unable to declare a constant of type 'int', only 'const(int)'.I don't see any situation in which we would need a constant of type "int" instead of "const (int)" or "invariant (int)". After all, if it is a *constant*, it should be either "const" or "invariant", no?
Dec 29 2007
Walter Bright wrote:Jérôme M. Berger wrote:Huh? So the fix is to make constants not const? Seems like the problem lies either in auto or in the expectation that const will not be transferred using auto. I would actually expect there to be an unconst!(X) template required in there or something if it's going to strip off const. --bbWalter Bright wrote:Consider the following: const int X = 3; auto i = X; i = 4; // error, i is const Essentially, it would make type inference far less useful.Yes, that could be done, but we're still stymied by the problem that we are unable to declare a constant of type 'int', only 'const(int)'.I don't see any situation in which we would need a constant of type "int" instead of "const (int)" or "invariant (int)". After all, if it is a *constant*, it should be either "const" or "invariant", no?
Dec 29 2007
Bill Baxter wrote:Walter Bright wrote:We don't have to worry about rvalue literals not being const, because: 2 = 3; is illegal anyway. But we do need to be concerned about its type, because of type inference.Jérôme M. Berger wrote:Huh? So the fix is to make constants not const?Walter Bright wrote:Consider the following: const int X = 3; auto i = X; i = 4; // error, i is const Essentially, it would make type inference far less useful.Yes, that could be done, but we're still stymied by the problem that we are unable to declare a constant of type 'int', only 'const(int)'.I don't see any situation in which we would need a constant of type "int" instead of "const (int)" or "invariant (int)". After all, if it is a *constant*, it should be either "const" or "invariant", no?Seems like the problem lies either in auto or in the expectation that const will not be transferred using auto. I would actually expect there to be an unconst!(X) template required in there or something if it's going to strip off const.Would you really prefer to do: auto i = Unconst!(X); ? If const were not transferred with auto, then we run smack into the tail const problem again.
Dec 29 2007
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Walter Bright wrote:Jérôme M. Berger wrote:Except that this is a different issue, on which I rambled at some length here: http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=64262 Basically, "auto" should drop the tail-most "const" if the language allows such types to exist and keep the "const" when it can't be dropped, e.g: - "const int" => "int"; - "const (T*)" => "(const (T))*" (if such is allowed); - "const (MyClass)" => "const (MyClass)" (since the tailmost type is actually the hidden reference type). This should be done whether the right-hand expression is a manifest constant, a "const" variable or an "invariant" variable. Jerome - -- +------------------------- Jerome M. BERGER ---------------------+ | mailto:jeberger free.fr | ICQ: 238062172 | | http://jeberger.free.fr/ | Jabber: jeberger jabber.fr | +---------------------------------+------------------------------+ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) iD8DBQFHdtTnd0kWM4JG3k8RAtvGAKCKVXzhXMe286aco7/2ruWJl4KbiACfYgoE 8UPHk7cbO7bDQt9Q04tDnj0= =DyHZ -----END PGP SIGNATURE-----Walter Bright wrote:Consider the following: const int X = 3; auto i = X; i = 4; // error, i is const Essentially, it would make type inference far less useful.Yes, that could be done, but we're still stymied by the problem that we are unable to declare a constant of type 'int', only 'const(int)'.I don't see any situation in which we would need a constant of type "int" instead of "const (int)" or "invariant (int)". After all, if it is a *constant*, it should be either "const" or "invariant", no?
Dec 29 2007
Jérôme M. Berger wrote:Basically, "auto" should drop the tail-most "const" if the language allows such types to exist and keep the "const" when it can't be dropped, e.g: - "const int" => "int"; - "const (T*)" => "(const (T))*" (if such is allowed); - "const (MyClass)" => "const (MyClass)" (since the tailmost type is actually the hidden reference type).I really did try to figure out how to make that work, but it just doesn't. Let's say we make a struct: struct MyInt { int x; ... and appropriate operator overloading ... } to make our own custom implementation of ints. What do we do with: const MyInt m = 3; auto n = m; Does n get const or not? If it is, now it is behaving differently from other types, and so is not a plug-in replacement. If it does not, what happens if MyInt has a pointer member? Suddenly, the const gets stripped from the pointer, and there is no const-correctness.
Dec 29 2007
On 12/29/07, Walter Bright <newshound1 digitalmars.com> wrote:What do we do with: const MyInt m = 3; auto n = m; Does n get const or not? If it is, now it is behaving differently from other types, and so is not a plug-in replacement. If it does not, what happens if MyInt has a pointer member? Suddenly, the const gets stripped from the pointer, and there is no const-correctness.In full agreement with you, Walter, having understood all your points (at last), but what if we allowed: const MyInt m = 3; auto n = m.dup; It would be no trouble at all for MyInt to supply a dup() function whose return value had type MyInt. The only question is, will it work for plain ints? const int m = 3; auto n = m.dup; And if not, can it be made to work? (That is, can we implement dup for all primitive types?)
Dec 29 2007
Janice Caron wrote:And if not, can it be made to work? (That is, can we implement dup for all primitive types?)We could, but my thinking hasn't progressed that far.
Jan 02 2008
On 12/30/07, Janice Caron <caron800 googlemail.com> wrote:In full agreement with you, Walter, having understood all your points (at last), but what if we allowed: const MyInt m = 3; auto n = m.dup; It would be no trouble at all for MyInt to supply a dup() function whose return value had type MyInt. The only question is, will it work for plain ints? const int m = 3; auto n = m.dup; And if not, can it be made to work? (That is, can we implement dup for all primitive types?)Actually, come to think of it, the implementation of MyInt.dup would have to be struct MyInt { int x; MyInt dup() const { return x.dup; } } so it actually wouldn't work /unless/ dup worked for primitive types.
Dec 29 2007
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Walter Bright wrote:What do we do with: const MyInt m = 3; auto n = m; Does n get const or not? If it is, now it is behaving differently from other types, and so is not a plug-in replacement. If it does not, what happens if MyInt has a pointer member? Suddenly, the const gets stripped from the pointer, and there is no const-correctness.OK, I see your point, but like Bill said I think the issue here is with the "auto" type inference rather than the "const". What is needed is for "auto" to be smarter than it is now, namely: - for atomic types, strip the const; - for pointers, if the language supports head const, then strip the tailmost const (ie make a mutable pointer to const data) otherwise keep the const; - for classes, keep the const; - for struct, the compiler already keeps track of whether the struct contains pointers or not because of the GC, doesn't it? In that case, if the struct contains pointers keep the const, and if it doesn't strip it (1); - in all cases, allow a "const auto" statement to force an "auto" declaration to be "const". This would work even if the right hand expression is not "const": int x = 42; const auto y = x; // y is now "const int" Jerome (1) It would be even nicer if the compiler could keep track of whether there are *mutable* pointers in the struct and strip the "const" from the "auto" variable if all pointers in the struct are "const" anyway, so it wouldn't break const-correctness: struct { int value; const int* pointer; } ConstStruct; struct { int value; int* pointer; } MutableStruct; const ConstStruct cs0; const MutableStruct ms0; auto cs1 = cs0; // <= cs1 is a ConstStruct since all // pointers inside are const anyway. auto ms1 = ms0; // <= ms1 is a const MutableStruct. cs0.value = 0; // Error, cs0 is const cs1.value = 1; // OK ms0.value = 2; // Error, ms0 is const ms1.value = 3; // Error, ms1 is const (2) In all I've said, you can replace "const" with "invariant" and the same arguments would apply. - -- +------------------------- Jerome M. BERGER ---------------------+ | mailto:jeberger free.fr | ICQ: 238062172 | | http://jeberger.free.fr/ | Jabber: jeberger jabber.fr | +---------------------------------+------------------------------+ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) iD8DBQFHd0yGd0kWM4JG3k8RAqAYAJ9ZAd4zCHvNIaHBsf5zfRlKKJd6WACdGyOo miKzodWMLGxjfeuJNO45Ig4= =NjKB -----END PGP SIGNATURE-----
Dec 29 2007
On 12/30/07, "Jérôme M. Berger" <jeberger free.fr> wrote:int x = 42; const auto y = x; // y is now "const int"The word "auto" is redundant here. int x = 42; const y = x;(1) It would be even nicer if the compiler could keep track of whether there are *mutable* pointers in the struct <snip>I'm in favor of handing responsibility for that decision to the programmer. const T x = whatever; auto y = x.dup; Then it becomes the programmer's responsibility to implement dup for each type T. .dup is already built into arrays. It would be trivial for Walter to supply a dup() function for primative types (dup()ing a const(int) must yield an int result). For structs and classes, it becomes the programmer's problem. I /think/ this will work, and it will definitely work better than making poor "auto" do different things for each type.
Dec 30 2007
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Janice Caron wrote:On 12/30/07, "Jérôme M. Berger" <jeberger free.fr> wrote:Well, the whole point of having an "auto" keyword is that it should do the right thing automagically. After all, it says so in the name! Moreover, this would allow "automatic manifest constants" to work (which was the main idea behind the suggestion: I was looking for a solution that would allow manifest constants to be of type "const int" instead of just "int"). Jerome - -- +------------------------- Jerome M. BERGER ---------------------+ | mailto:jeberger free.fr | ICQ: 238062172 | | http://jeberger.free.fr/ | Jabber: jeberger jabber.fr | +---------------------------------+------------------------------+ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) iD8DBQFHeL7Rd0kWM4JG3k8RAjskAJ44IRFUSZtBTnGEoiM8BgAvyFnKiACeICyB C10W7/hE0Yq5JrfIiWW3FeI= =t+QJ -----END PGP SIGNATURE-----(1) It would be even nicer if the compiler could keep track of whether there are *mutable* pointers in the struct <snip>I'm in favor of handing responsibility for that decision to the programmer. const T x = whatever; auto y = x.dup; Then it becomes the programmer's responsibility to implement dup for each type T. .dup is already built into arrays. It would be trivial for Walter to supply a dup() function for primative types (dup()ing a const(int) must yield an int result). For structs and classes, it becomes the programmer's problem. I /think/ this will work, and it will definitely work better than making poor "auto" do different things for each type.
Dec 31 2007
Jérôme M. Berger wrote:-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Walter Bright wrote:That doesn't really make sense. You could push off const one level: ms1.value = 3; // Fine *ms1.pointer = 3; // Error; pointer is const That would make sense, but it would be hard to do, and it would be hard for a programmer to think "okay, I just did this assignment, now what is const in the struct and what isn't?" Structs make const hard. It'd be easier with just classes, I think.What do we do with: const MyInt m = 3; auto n = m; Does n get const or not? If it is, now it is behaving differently from other types, and so is not a plug-in replacement. If it does not, what happens if MyInt has a pointer member? Suddenly, the const gets stripped from the pointer, and there is no const-correctness.OK, I see your point, but like Bill said I think the issue here is with the "auto" type inference rather than the "const". What is needed is for "auto" to be smarter than it is now, namely: - for atomic types, strip the const; - for pointers, if the language supports head const, then strip the tailmost const (ie make a mutable pointer to const data) otherwise keep the const; - for classes, keep the const; - for struct, the compiler already keeps track of whether the struct contains pointers or not because of the GC, doesn't it? In that case, if the struct contains pointers keep the const, and if it doesn't strip it (1); - in all cases, allow a "const auto" statement to force an "auto" declaration to be "const". This would work even if the right hand expression is not "const": int x = 42; const auto y = x; // y is now "const int" Jerome (1) It would be even nicer if the compiler could keep track of whether there are *mutable* pointers in the struct and strip the "const" from the "auto" variable if all pointers in the struct are "const" anyway, so it wouldn't break const-correctness: struct { int value; const int* pointer; } ConstStruct; struct { int value; int* pointer; } MutableStruct; const ConstStruct cs0; const MutableStruct ms0; auto cs1 = cs0; // <= cs1 is a ConstStruct since all // pointers inside are const anyway. auto ms1 = ms0; // <= ms1 is a const MutableStruct.
Dec 30 2007
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Christopher Wright wrote:Jérôme M. Berger wrote:Yes and no: it would actually require the compiler to create a new struct type that the programmer didn't request explicitly: ms1 would be of type struct { int value; const int* pointer; } SomeInternalStructTypeThatIsDifferentFromConstStructAndFromMutableStruct; This could cause lots of other issues like: const MutableStruct ms2 = ms1; // <= Error cannot convert // implicitly, but it should. My suggestion wasn't perfect, but it should be reasonably straightforward to implement in the compiler without introducing any side-effects elsewhere (I hope).Walter Bright wrote:That doesn't really make sense. You could push off const one level: ms1.value = 3; // Fine *ms1.pointer = 3; // Error; pointer is const That would make sense, but it would be hard to do, and it would be hard for a programmer to think "okay, I just did this assignment, now what is const in the struct and what isn't?"What do we do with: const MyInt m = 3; auto n = m; Does n get const or not? If it is, now it is behaving differently from other types, and so is not a plug-in replacement. If it does not, what happens if MyInt has a pointer member? Suddenly, the const gets stripped from the pointer, and there is no const-correctness.OK, I see your point, but like Bill said I think the issue here is with the "auto" type inference rather than the "const". What is needed is for "auto" to be smarter than it is now, namely: - for atomic types, strip the const; - for pointers, if the language supports head const, then strip the tailmost const (ie make a mutable pointer to const data) otherwise keep the const; - for classes, keep the const; - for struct, the compiler already keeps track of whether the struct contains pointers or not because of the GC, doesn't it? In that case, if the struct contains pointers keep the const, and if it doesn't strip it (1); - in all cases, allow a "const auto" statement to force an "auto" declaration to be "const". This would work even if the right hand expression is not "const": int x = 42; const auto y = x; // y is now "const int" Jerome (1) It would be even nicer if the compiler could keep track of whether there are *mutable* pointers in the struct and strip the "const" from the "auto" variable if all pointers in the struct are "const" anyway, so it wouldn't break const-correctness: struct { int value; const int* pointer; } ConstStruct; struct { int value; int* pointer; } MutableStruct; const ConstStruct cs0; const MutableStruct ms0; auto cs1 = cs0; // <= cs1 is a ConstStruct since all // pointers inside are const anyway. auto ms1 = ms0; // <= ms1 is a const MutableStruct.Structs make const hard. It'd be easier with just classes, I think.True, but since structs already exist, we're stuck with them so we (well, Walter) must find a way to make const work with them. Jerome - -- +------------------------- Jerome M. BERGER ---------------------+ | mailto:jeberger free.fr | ICQ: 238062172 | | http://jeberger.free.fr/ | Jabber: jeberger jabber.fr | +---------------------------------+------------------------------+ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) iD8DBQFHeCh/d0kWM4JG3k8RAj49AJ9LFyp+AbjjtyVsrgsyMHep0sm8jACfT2Ra 8txL7dsLXvbNoi+EmrbKqew= =blb1 -----END PGP SIGNATURE-----
Dec 30 2007
Jérôme M. Berger wrote:OK, I see your point, but like Bill said I think the issue here is with the "auto" type inference rather than the "const". What is needed is for "auto" to be smarter than it is now, namely: - for atomic types, strip the const; - for pointers, if the language supports head const, then strip the tailmost const (ie make a mutable pointer to const data) otherwise keep the const; - for classes, keep the const; - for struct, the compiler already keeps track of whether the struct contains pointers or not because of the GC, doesn't it? In that case, if the struct contains pointers keep the const, and if it doesn't strip it (1); - in all cases, allow a "const auto" statement to force an "auto" declaration to be "const". This would work even if the right hand expression is not "const": int x = 42; const auto y = x; // y is now "const int"I did think of doing that way, but: 1) it's too complicated to explain, too many special cases 2) Andrei pointed out to me that now the const-ness of a struct can depend on its private data types. This would suck for users, as private data is supposed to be opaque to users.
Jan 02 2008
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Walter Bright wrote:I did think of doing that way, but: 1) it's too complicated to explain, too many special casesTrue2) Andrei pointed out to me that now the const-ness of a struct can depend on its private data types. This would suck for users, as private data is supposed to be opaque to users.True, I hadn't thought of that. Too bad, it would have been a pretty nifty feature. Jerome PS: Just so we're sure what I'm agreeing about here: automatic manifest constants probably can't work (unless we drop the "auto" type inference which is too useful to remove). OTOH, I still think that using "enum" for them is a poor choice. - -- +------------------------- Jerome M. BERGER ---------------------+ | mailto:jeberger free.fr | ICQ: 238062172 | | http://jeberger.free.fr/ | Jabber: jeberger jabber.fr | +---------------------------------+------------------------------+ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) iD8DBQFHe4cdd0kWM4JG3k8RAm7jAJ4rG2AOe9jOMCzRl/xlSGzBn+kczQCeJGL5 zln2XiVTbC9O5QF3wXlvIPE= =E2Ur -----END PGP SIGNATURE-----
Jan 02 2008
Walter Bright wrote:Jérôme M. Berger wrote:That is a valid problem. But it is a problem with the const semantics and the type inference functionality. It is not a problem with the declaration of manifest constants, so please don't introduce a problem in one place (making 'enum' not mean "enumeration" anymore, among other things) to fix a problem that has its roots in another place ('auto')... :X -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DBasically, "auto" should drop the tail-most "const" if the language allows such types to exist and keep the "const" when it can't be dropped, e.g: - "const int" => "int"; - "const (T*)" => "(const (T))*" (if such is allowed); - "const (MyClass)" => "const (MyClass)" (since the tailmost type is actually the hidden reference type).I really did try to figure out how to make that work, but it just doesn't. Let's say we make a struct: struct MyInt { int x; ... and appropriate operator overloading ... } to make our own custom implementation of ints. What do we do with: const MyInt m = 3; auto n = m; Does n get const or not? If it is, now it is behaving differently from other types, and so is not a plug-in replacement. If it does not, what happens if MyInt has a pointer member? Suddenly, the const gets stripped from the pointer, and there is no const-correctness.
Jan 05 2008
Jérôme M. Berger wrote:-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Walter Bright wrote:You mean head-most const (or just head const), not tail-most const. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DJérôme M. Berger wrote:Except that this is a different issue, on which I rambled at some length here: http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=64262 Basically, "auto" should drop the tail-most "const" if the language allows such types to exist and keep the "const" when it can't be dropped, e.g: - "const int" => "int"; - "const (T*)" => "(const (T))*" (if such is allowed); - "const (MyClass)" => "const (MyClass)" (since the tailmost type is actually the hidden reference type). This should be done whether the right-hand expression is a manifest constant, a "const" variable or an "invariant" variable. Jerome - --Walter Bright wrote:Consider the following: const int X = 3; auto i = X; i = 4; // error, i is const Essentially, it would make type inference far less useful.Yes, that could be done, but we're still stymied by the problem that we are unable to declare a constant of type 'int', only 'const(int)'.I don't see any situation in which we would need a constant of type "int" instead of "const (int)" or "invariant (int)". After all, if it is a *constant*, it should be either "const" or "invariant", no?
Jan 05 2008
Walter Bright schrieb:Jérôme M. Berger wrote:Why is it neccessary to transfer the const for value types? The assignment always makes a copy, so manipulation is OK?Walter Bright wrote:Consider the following: const int X = 3; auto i = X; i = 4; // error, i is const Essentially, it would make type inference far less useful.Yes, that could be done, but we're still stymied by the problem that we are unable to declare a constant of type 'int', only 'const(int)'.I don't see any situation in which we would need a constant of type "int" instead of "const (int)" or "invariant (int)". After all, if it is a *constant*, it should be either "const" or "invariant", no?
Dec 29 2007
Frank Benoit wrote:Why is it neccessary to transfer the const for value types? The assignment always makes a copy, so manipulation is OK?Very good question. I tried to answer it in my reply to Jerome.
Dec 29 2007
On Sat, 29 Dec 2007 14:43:28 -0800, Walter Bright wrote:Jérôme M. Berger wrote:I think I'm confused here. Are you saying Walter, that in this example, 'i' would NOT be const? My simple reasoning goes like this ... const int X = 3; declares that X is a 'const int' data type. auto i = X; declares that 'i' automatically takes on the data type of 'X', thus 'i' is also a 'const int' and its initial (and only) value is the same as in 'X'. i = 4; should be an error because i is immutable. To have 'auto' strip off const should be an explicit thing. This would enable us to have a better definition of APIs too, which is something you want. mutable auto i = X; // by way of example -- Derek Parnell Melbourne, Australia skype: derek.j.parnellWalter Bright wrote:Consider the following: const int X = 3; auto i = X; i = 4; // error, i is const Essentially, it would make type inference far less useful.Yes, that could be done, but we're still stymied by the problem that we are unable to declare a constant of type 'int', only 'const(int)'.I don't see any situation in which we would need a constant of type "int" instead of "const (int)" or "invariant (int)". After all, if it is a *constant*, it should be either "const" or "invariant", no?
Dec 29 2007
Derek Parnell wrote:On Sat, 29 Dec 2007 14:43:28 -0800, Walter Bright wrote:No, I'm saying it would be const(int), which is why we need a way to type a constant as just plain int.Jérôme M. Berger wrote:I think I'm confused here. Are you saying Walter, that in this example, 'i' would NOT be const?Walter Bright wrote:Consider the following: const int X = 3; auto i = X; i = 4; // error, i is const Essentially, it would make type inference far less useful.Yes, that could be done, but we're still stymied by the problem that we are unable to declare a constant of type 'int', only 'const(int)'.I don't see any situation in which we would need a constant of type "int" instead of "const (int)" or "invariant (int)". After all, if it is a *constant*, it should be either "const" or "invariant", no?My simple reasoning goes like this ... const int X = 3; declares that X is a 'const int' data type. auto i = X; declares that 'i' automatically takes on the data type of 'X', thus 'i' is also a 'const int' and its initial (and only) value is the same as in 'X'. i = 4; should be an error because i is immutable.Exactly.
Dec 29 2007
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Walter Bright wrote:Jérôme M. Berger wrote:OTOH, having something that's a constant but has type "int" instead of "const (int)" or "invariant (int)" could cause problems with generic programming. For example with something like this: - -------------------->8==================== static if (is (typeof (x) : int) x = 42; else static if ((is (typeof (x) : const (int)) || (is (typeof (x) : invariant (int))) processImmutableInts(); else static assert (0, "Can only handle ints"); ====================8<-------------------- If "x" is in fact a manifest constant, this code will think it is mutable and try to assign to it but the compiler will then refuse the assignment... Jerome - -- +------------------------- Jerome M. BERGER ---------------------+ | mailto:jeberger free.fr | ICQ: 238062172 | | http://jeberger.free.fr/ | Jabber: jeberger jabber.fr | +---------------------------------+------------------------------+ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) iD8DBQFHeMFHd0kWM4JG3k8RAj9IAKC+m/8C7+QjF3Kza567mGnaGCC15ACfRp4q 1TCS8yIcZuMG9nBgNfnIDaw= =wZ6N -----END PGP SIGNATURE-----Walter Bright wrote:Consider the following: const int X = 3; auto i = X; i = 4; // error, i is const Essentially, it would make type inference far less useful.Yes, that could be done, but we're still stymied by the problem that we are unable to declare a constant of type 'int', only 'const(int)'.I don't see any situation in which we would need a constant of type "int" instead of "const (int)" or "invariant (int)". After all, if it is a *constant*, it should be either "const" or "invariant", no?
Dec 31 2007
Jérôme M. Berger wrote:-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Walter Bright wrote:Thanks for mentioning that. That's what I was thinking too. Walter said something about how literals are plain types, and it works fine because you can't assign to them since they aren't lvalues. But it seems like for generic programming it would be more useful if literals did get typed as const. Unless there's some other obvious way to test for lvalueness. --bbJérôme M. Berger wrote:OTOH, having something that's a constant but has type "int" instead of "const (int)" or "invariant (int)" could cause problems with generic programming. For example with something like this: - -------------------->8==================== static if (is (typeof (x) : int) x = 42; else static if ((is (typeof (x) : const (int)) || (is (typeof (x) : invariant (int))) processImmutableInts(); else static assert (0, "Can only handle ints"); ====================8<-------------------- If "x" is in fact a manifest constant, this code will think it is mutable and try to assign to it but the compiler will then refuse the assignment...Walter Bright wrote:Consider the following: const int X = 3; auto i = X; i = 4; // error, i is const Essentially, it would make type inference far less useful.Yes, that could be done, but we're still stymied by the problem that we are unable to declare a constant of type 'int', only 'const(int)'.I don't see any situation in which we would need a constant of type "int" instead of "const (int)" or "invariant (int)". After all, if it is a *constant*, it should be either "const" or "invariant", no?
Dec 31 2007
Jérôme M. Berger wrote:-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Walter Bright wrote:You basically want this to fail: --- enum int foo = 5; template Something (alias arg) { // ... } Something!(foo); --- Since it's the equivalent of: --- template Something (alias arg) { // ... } Something!(5); --- And that would be a substitution failure, hopefully with a special error message telling you it's a compile-time constant so you can't use alias with it. The workaround being, assign it and then pass it. I don't know of a situation where it would be advantageous to use an alias template parameter where a compile-time constant would make sense.Jérôme M. Berger wrote:OTOH, having something that's a constant but has type "int" instead of "const (int)" or "invariant (int)" could cause problems with generic programming. For example with something like this: - -------------------->8==================== static if (is (typeof (x) : int) x = 42; else static if ((is (typeof (x) : const (int)) || (is (typeof (x) : invariant (int))) processImmutableInts(); else static assert (0, "Can only handle ints"); ====================8<--------------------Walter Bright wrote:Consider the following: const int X = 3; auto i = X; i = 4; // error, i is const Essentially, it would make type inference far less useful.Yes, that could be done, but we're still stymied by the problem that we are unable to declare a constant of type 'int', only 'const(int)'.I don't see any situation in which we would need a constant of type "int" instead of "const (int)" or "invariant (int)". After all, if it is a *constant*, it should be either "const" or "invariant", no?
Dec 31 2007
Walter Bright wrote:Jérôme M. Berger wrote:I'll ignore for the moment the (very tricky) problem of assigning copies of const structs. Just for basic types, we could easily solve this by requiring the syntax "const auto" when we wanted a constant: const int X = 3; auto i = X; const auto j = X; i = 4; // legal, typeof(i) is int j = 4; // error, j is const Doesn't it make sense that type deduction (which deals with how the variable was declared in the *past*) should be orthogonal from constness (which deals with how the variable will be used in the *future*)?Walter Bright wrote:Consider the following: const int X = 3; auto i = X; i = 4; // error, i is const Essentially, it would make type inference far less useful.Yes, that could be done, but we're still stymied by the problem that we are unable to declare a constant of type 'int', only 'const(int)'.I don't see any situation in which we would need a constant of type "int" instead of "const (int)" or "invariant (int)". After all, if it is a *constant*, it should be either "const" or "invariant", no?
Jan 02 2008
On 1/2/08, Russell Lewis <webmaster villagersonline.com> wrote:I'll ignore for the moment the (very tricky) problem of assigning copies of const structs. Just for basic types, we could easily solve this by requiring the syntax "const auto" when we wanted a constant: const int X = 3; auto i = X; const auto j = X; i = 4; // legal, typeof(i) is intBut typeof(i) /isn't/ int. typeof(i) is const(int). The problem is not how to make a const copy of a const primitive - it's how to make a mutable copy of a const primitive. That's why Walter is introducing manifest constants: enum int x = 3; auto i = x; // typeof(i) is int const j = x; // typeof(i) is const(int) and why I suggested allowing primitive types to have a .dup property const int x = 3; auto i = x.dup; // typeof(i) is int auto j = x; // typeof(i) is const(int)Doesn't it make sense that type deduction (which deals with how the variable was declared in the *past*) should be orthogonal from constness (which deals with how the variable will be used in the *future*)?Type deduction only means that auto x = y; is equivalent to typeof(y) x = y; and if typeof(y) is const(int), well then, so will x be.
Jan 02 2008
Janice Caron wrote:On 1/2/08, Russell Lewis <webmaster villagersonline.com> wrote:I was suggesting how things *should* be, not how they are. Sorry if I didn't make that clear.I'll ignore for the moment the (very tricky) problem of assigning copies of const structs. Just for basic types, we could easily solve this by requiring the syntax "const auto" when we wanted a constant: const int X = 3; auto i = X; const auto j = X; i = 4; // legal, typeof(i) is intBut typeof(i) /isn't/ int. typeof(i) is const(int). The problem is not how to make a const copy of a const primitive - it's how to make a mutable copy of a const primitive.
Jan 02 2008
Russell Lewis wrote:Janice Caron wrote:Hmmm...maybe the problem isn't with auto, after all. Maybe what I'm really suggesting is that (with primitive types, remember I'm explicitly not considering structs) when you use a const value on the right-hand side, then the expression is not const (since you are copying the value). OTOH, when you use it on the left side, it of course must be const. Sort of like saying "the variable X" is const, but the value it contains (3) is not. If you think of the variable as a box that holds a value, it makes sense. I haven't thought this one through deeply yet, so there might be a problem with it, but I thought I'd throw the ponder out.On 1/2/08, Russell Lewis <webmaster villagersonline.com> wrote:I was suggesting how things *should* be, not how they are. Sorry if I didn't make that clear.I'll ignore for the moment the (very tricky) problem of assigning copies of const structs. Just for basic types, we could easily solve this by requiring the syntax "const auto" when we wanted a constant: const int X = 3; auto i = X; const auto j = X; i = 4; // legal, typeof(i) is intBut typeof(i) /isn't/ int. typeof(i) is const(int). The problem is not how to make a const copy of a const primitive - it's how to make a mutable copy of a const primitive.
Jan 02 2008
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Fri, 28 Dec 2007 21:59:54 +0100, "Jérôme M. Berger" wrote:Right. Replace "const" by "invariant" in my comment and the main point still stands: couldn't the compiler determine automatically if we take the address of an invariant variable and allocate memory for it or not based on that? This would remove the need for a special keyword/syntax for manifest constants: just declare them as "invariant" and let the compiler do the work.In order to do that, won't the compiler need to have access to all the source code for the application? If so, how can the compiler do it when given some source code and some object code to build the application? - -- Derek Parnell Melbourne, Australia skype: derek.j.parnell -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (MingW32) - WinPT 1.2.0 iD8DBQFHdXOUB2Z2alRbg5gRAgZlAKCna1d2thleArou/ETBguEjzwCUHwCfbCAg uq1e/ExdqDzU33RGI2SDfvU= =Gi+6 -----END PGP SIGNATURE-----
Dec 28 2007
On 12/28/07, Derek Parnell <derek psych.ward> wrote:In order to do that, won't the compiler need to have access to all the source code for the application?No. (So the rest of your question, "If so..." doesn't apply) That said, Walter has already explained that this idea presents difficulties pertaining to tail-constness, and so can't be done. Just - not for the reason that you're implying.
Dec 28 2007
On Fri, 28 Dec 2007 22:56:27 +0000, Janice Caron wrote:On 12/28/07, Derek Parnell <derek psych.ward> wrote:Why not? If what we are talking about is having the compiler detect if some code is taking the address of a constant value, doesn't the compiler need to see the code that does that? And if that code is in an object file and not a source file, then how will the compiler find out that the address is being taken? -- Derek Parnell Melbourne, Australia skype: derek.j.parnellIn order to do that, won't the compiler need to have access to all the source code for the application?No.
Dec 28 2007
Derek Parnell wrote:If what we are talking about is having the compiler detect if some code is taking the address of a constant value, doesn't the compiler need to see the code that does that? And if that code is in an object file and not a source file, then how will the compiler find out that the address is being taken?What happens is the compiler emits data to the object file whenever the address of a constant is taken, regardless of what module defines the constant. Then, the linker removes the duplicates.
Dec 28 2007
On 12/28/07, Derek Parnell <derek psych.ward> wrote:On Fri, 28 Dec 2007 22:56:27 +0000, Janice Caron wrote:I was going to answer this, but Walter got there first and answered it before me. Ho hum. Still, I'll paraphrase. In file_1: const int x = 42; /could/, if we were applying this logic, compile to an object file in which zero bytes were reserved for x. Then, in file_2: import file_1; const int * px = &x; the object file would contain storage for x, in a segment all by itself. The clever part is that the /linker/, not the compiler, is able to remove duplicate segments, so if the same segment occurs in file_3.obj or file_4.obj, it will only appear in the final .exe once.On 12/28/07, Derek Parnell <derek psych.ward> wrote:Why not? If what we are talking about is having the compiler detect if some code is taking the address of a constant value, doesn't the compiler need to see the code that does that? And if that code is in an object file and not a source file, then how will the compiler find out that the address is being taken?In order to do that, won't the compiler need to have access to all the source code for the application?No.
Dec 29 2007
Walter Bright wrote:Jérôme M. Berger wrote:Surely you don't want to make a language that's less clear and/or pleasant for its users, because it's slightly easier to implement!Walter Bright wrote:Not really, just loosened up the restrictions on enum. The implementation code is actually simpler <g>.Jérôme M. Berger wrote:This is an artificial distinction: you *are* adding a fourth way to declare a constant,:(Yeah, I figure I'll get fricasseed over that one. The most compelling argument is that we already have 3 ways to declare a constant, adding a fourth gets very difficult to justify. As opposed to a minor extension to enums.But I thought from discussion that enum wasn't allowed to be used when declaring multiple manifest constants -- a rule more akin to saying that in some contexts it's legal to define arrays so long as they have exactly one element. -- Jamesthe only question is what syntax to use: either a counter-intuitive extension to enums or a new keyword (or a minor extension to the alias keyword as was suggested by somebody).I found the "use an alias when declaring one constant" and "use an enum when declaring more than one constant" to be difficult to justify. It's like saying arrays with only one element should not be allowed.
Dec 28 2007
James Dennett wrote:Walter Bright wrote:No, but a simple, clean implementation can be an indication of a simple, clean design. If the implementation is larded up with special case code, that's a flag that perhaps the users also see that lard.Not really, just loosened up the restrictions on enum. The implementation code is actually simpler <g>.Surely you don't want to make a language that's less clear and/or pleasant for its users, because it's slightly easier to implement!enum { X = 3, Y = 3L } defines two manifest constants.But I thought from discussion that enum wasn't allowed to be used when declaring multiple manifest constants -- a rule more akin to saying that in some contexts it's legal to define arrays so long as they have exactly one element.the only question is what syntax to use: either a counter-intuitive extension to enums or a new keyword (or a minor extension to the alias keyword as was suggested by somebody).I found the "use an alias when declaring one constant" and "use an enum when declaring more than one constant" to be difficult to justify. It's like saying arrays with only one element should not be allowed.
Dec 28 2007
Walter Bright wrote:James Dennett wrote:It can indicate, but it's not a 100% guarantee of such! -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DWalter Bright wrote:No, but a simple, clean implementation can be an indication of a simple, clean design. If the implementation is larded up with special case code, that's a flag that perhaps the users also see that lard.Not really, just loosened up the restrictions on enum. The implementation code is actually simpler <g>.Surely you don't want to make a language that's less clear and/or pleasant for its users, because it's slightly easier to implement!
Jan 05 2008
Walter Bright wrote:Jérôme M. Berger wrote:And rightfully so. This is one of the worse decisions among the bad ones in the D history.:(Yeah, I figure I'll get fricasseed over that one.argument is that we already have 3 ways to declare a constant, adding a fourth gets very difficult to justify. As opposed to a minor extension to enums.Not good enough. -- Lars Ivar Igesund blog at http://larsivi.net DSource, #d.tango & #D: larsivi Dancing the Tango
Dec 28 2007
Lars Ivar Igesund wrote:Walter Bright wrote:It'll do. I'd say it's bad, but not that bad (I think "manifest" looked better, personally -- almost pays to go back in time and start adopting the ideas that worked several decades ago... if they indeed did work). Like everything in D, it's one of: (1) we eventually get used to it (2) it eventually gets rejected and deprecated by the designer(s) (3) or d gets abandoned. :-P This is only a D 2.0 feature, afterall. It doesn't touch v 1.0. I still think "foreach_reverse" was among the worst... but I guess everybody has a pet peeve. If we need to sacrifice "enum" for the sake of a better "const" design, maybe it's worth it... but this "new" design better be good. :D -JJRJérôme M. Berger wrote:And rightfully so. This is one of the worse decisions among the bad ones in the D history.:(Yeah, I figure I'll get fricasseed over that one.argument is that we already have 3 ways to declare a constant, adding a fourth gets very difficult to justify. As opposed to a minor extension to enums.Not good enough.
Dec 28 2007
John Reimer wrote:Lars Ivar Igesund wrote:Considering that none of the "established" bad decisions from 1.0 seems to be fixed (yet) in 2.0, we are currently gaining in the bad end? Even if there is a lot of nice stuff in there too. FWIW, I think enum is on the same level as foreach_reverse, although that one exposed the problem with keywording such a special case. The usecase implemented with enum is at least valid enough. -- Lars Ivar Igesund blog at http://larsivi.net DSource, #d.tango & #D: larsivi Dancing the TangoWalter Bright wrote:It'll do. I'd say it's bad, but not that bad (I think "manifest" looked better, personally -- almost pays to go back in time and start adopting the ideas that worked several decades ago... if they indeed did work). Like everything in D, it's one of: (1) we eventually get used to it (2) it eventually gets rejected and deprecated by the designer(s) (3) or d gets abandoned. :-PJérôme M. Berger wrote:And rightfully so. This is one of the worse decisions among the bad ones in the D history.:(Yeah, I figure I'll get fricasseed over that one.argument is that we already have 3 ways to declare a constant, adding a fourth gets very difficult to justify. As opposed to a minor extension to enums.Not good enough.
Dec 28 2007
Lars Ivar Igesund wrote:True. Can't argue with that. -JJRIt'll do. I'd say it's bad, but not that bad (I think "manifest" looked better, personally -- almost pays to go back in time and start adopting the ideas that worked several decades ago... if they indeed did work). Like everything in D, it's one of: (1) we eventually get used to it (2) it eventually gets rejected and deprecated by the designer(s) (3) or d gets abandoned. :-PConsidering that none of the "established" bad decisions from 1.0 seems to be fixed (yet) in 2.0, we are currently gaining in the bad end? Even if there is a lot of nice stuff in there too. FWIW, I think enum is on the same level as foreach_reverse, although that one exposed the problem with keywording such a special case. The usecase implemented with enum is at least valid enough.
Dec 28 2007
"Walter Bright" wroteJérôme M. Berger wrote:Whether you use enum or manifest or some other keyword, you are already adding a fourth method, as Jerome pointed out. But regardless, it is not so much the adding of the new method as it is the shoehorning of the word enum into something it was not meant to be. Enum stands for enumeration, and is traditionally used to define a new type, which can only be one of several values. In this case, we don't want a new type. We want to declare a read-only value of an already defined type.:(Yeah, I figure I'll get fricasseed over that one. The most compelling argument is that we already have 3 ways to declare a constant, adding a fourth gets very difficult to justify.As opposed to a minor extension to enums.Um... this is not minor :) This is a complete redefinition of what enum means. -Steve
Dec 28 2007
Steven Schveighoffer wrote:enum is already used to declare arbitrary constants *that do not have an enum type* in C, C++, and D.As opposed to a minor extension to enums.Um... this is not minor :) This is a complete redefinition of what enum means.
Dec 28 2007
Walter Bright wrote:Steven Schveighoffer wrote:And, several times this argument has been rebuffed: The reason people do this in D is usually under duress because of problems using "const". It wasn't done because it was a preferred way nor because "enum" was something that clearly indicated its purpose. Laying claim to this argument as a reasonable promotion of "enum" is not the best approach to proving to the D group that "enum" was an optimal choice. Like I said, it will work. But you probably already know that it will be accepted quite begrudgingly. Just wanted to point that out again. :) -JJRenum is already used to declare arbitrary constants *that do not have an enum type* in C, C++, and D.As opposed to a minor extension to enums.Um... this is not minor :) This is a complete redefinition of what enum means.
Dec 28 2007
"Walter Bright" wroteSteven Schveighoffer wrote:The implementation does not follow the semantics. An enum is still conceptually a group of related definitions that have the same type (i.e. enumeration). You are proposing to redefine this as a group of unrelated definitions that can have different types. Yes, people use enum to define constants in code, but they are usually all related, even though they don't have to be, and they are all of the same type because conceptually, *an enumeration is a collection of like-type values that can be assigned to a variable of the same type*. I like the way this is enforced today. This is going to confuse the hell out of all newcomers, and I think there are very few people who use D that actually think this is a good idea (myself included). There are much better ways to solve this problem than destroying the traditional meaning of enum. -Steveenum is already used to declare arbitrary constants *that do not have an enum type* in C, C++, and D.As opposed to a minor extension to enums.Um... this is not minor :) This is a complete redefinition of what enum means.
Dec 28 2007
Steven Schveighoffer wrote:This is going to confuse the hell out of all newcomers, and I think there are very few people who use D that actually think this is a good idea (myself included). There are much better ways to solve this problem than destroying the traditional meaning of enum.I understand your point, but also consider that adding yet a fourth way to declare constants is not going to be illuminating for newcomers, and it makes D look like a mishmash. Furthermore, it does not destroy the meaning of enum. Already, you can do this in C, C++ and D: enum { x = 1, y = 2 } // x and y are int's we just extend it a bit so that they don't have to be all the same type: enum { x = 1, y = 2L } // x is int, y is long and allow the { } to be dropped if only one declaration is present. We also drop the requirement that enum types be only integral ones.
Dec 28 2007
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Walter Bright wrote:Steven Schveighoffer wrote:Except that you're already "adding a fourth way to declare constants" so it is already "not illuminating for newcomers" and it already "makes D look like a mishmash". But using "enum" only aggravates the situation: newcomers will face something that they think they know ("enum") but actually don't really.This is going to confuse the hell out of all newcomers, and I think there are very few people who use D that actually think this is a good idea (myself included). There are much better ways to solve this problem than destroying the traditional meaning of enum.I understand your point, but also consider that adding yet a fourth way to declare constants is not going to be illuminating for newcomers, and it makes D look like a mishmash.Furthermore, it does not destroy the meaning of enum. Already, you can do this in C, C++ and D: enum { x = 1, y = 2 } // x and y are int'sThere is an additional implied meaning here: x and y are related: they are either alternate choices for some value or flags that may be or'ed together. No compiler enforces that, but I've never seen it used to declare wildly unrelated values (and I would consider it a poor coding practice). Jerome - -- +------------------------- Jerome M. BERGER ---------------------+ | mailto:jeberger free.fr | ICQ: 238062172 | | http://jeberger.free.fr/ | Jabber: jeberger jabber.fr | +---------------------------------+------------------------------+ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) iD8DBQFHdWKbd0kWM4JG3k8RAn8vAKCcYy/hTwQWZ2mstcf2RIzWkni7SACffJzE qlVXlIS+vohfe1JK96Wj2kI= =7jNU -----END PGP SIGNATURE-----
Dec 28 2007
On 12/28/07, "Jérôme M. Berger" <jeberger free.fr> wrote:Actually, I think that's a fifth way. You may have forgotten about real pi() { return 3.14159265359; } Since we would hope that real x = pi; will be inlined by the compiler, it would yield the effect of a manifest constant! :)I understand your point, but also consider that adding yet a fourth way to declare constants
Dec 28 2007
Janice Caron Wrote:On 12/28/07, "Jérôme M. Berger" <jeberger free.fr> wrote:Except you need a specific set of compiler and linker options for that effect. (-inline, -L--gc-sections) No way to tell the compiler that you want a specific function inlined and omitted from output.Actually, I think that's a fifth way. You may have forgotten about real pi() { return 3.14159265359; } Since we would hope that real x = pi; will be inlined by the compiler, it would yield the effect of a manifest constant! :)I understand your point, but also consider that adding yet a fourth way to declare constants
Dec 28 2007
"Walter Bright" wroteSteven Schveighoffer wrote:This is worse. You are now changing the meaning of enum as it was in C or C++. So to a newcomer who knows what enum is, they will breeze through that section of the manual, thinking 'D has enums, cool, I already know how to use those' and be utterly confused when they come across an example like: enum { x = 1, y = "hello" }This is going to confuse the hell out of all newcomers, and I think there are very few people who use D that actually think this is a good idea (myself included). There are much better ways to solve this problem than destroying the traditional meaning of enum.I understand your point, but also consider that adding yet a fourth way to declare constants is not going to be illuminating for newcomersit makes D look like a mishmash.That's a very subjective statement. I don't think it does. I think multiple uses for the same keyword look messier than multiple keywords that mean distinct things.Furthermore, it does not destroy the meaning of enum. Already, you can do this in C, C++ and D: enum { x = 1, y = 2 } // x and y are int's we just extend it a bit so that they don't have to be all the same type: enum { x = 1, y = 2L } // x is int, y is longNo, it's a redefinition. Now enum does not mean enumeration, it means manifest constant. Oh and by the way, if you assign a symbol name to an enum, it becomes a traditional enum (with a type and the requirement that all the values have the same type). Having one keyword mean two different things, when used in slightly different ways is very very confusing. Consider this: enum Foo { x = 'a' } Now we remove Foo: enum { x = 'a' } Now x is a char, where Foo.x was an int? That is very confusing. Especially if you are reading a long list of constants, and can't remember whether the type was specified at the top or is specified by the rvalue. Here's an analogy: Imagine a language which did not have pointers. But some clever coder figured out how to use ints as pointers. And then the developer of the langauge says 'were going to support int as a pointer if you put a dot after it, because people already use ints as pointers anyways' The example is simple, and probably unrealistic, but it captures the "oh my god, what is he thinking" reaction that I have to this change.We also drop the requirement that enum types be only integral ones.This, I agree with and support. It's the multiple types in one enum declaration that is really confusing, and the loosening of the definition that an enum is an enumeration of related values instead of a list of constants. -Steve
Dec 28 2007
Steven Schveighoffer wrote:Consider this: enum Foo { x = 'a' } Now we remove Foo: enum { x = 'a' } Now x is a char, where Foo.x was an int? That is very confusing.C, C++, and D already work that way. Such are in common use, and I've not heard a complaint that it is very confusing. For example, it's in std.c.windows.windows.d (among many), and there's not been a single comment on it (pro or con) in 6 years in this n.g. Extending it to allow heterogeneous types is not a big step, nor does it break any existing code or usage.
Dec 28 2007
"Walter Bright" wroteSteven Schveighoffer wrote:You missed the point of my example :) I'm not debating anonymous enumerations and whether they should exist or not. I'm saying that the definition of enum working like an enumeration, or working like a manifest list, based on whether the enumeration is named or anonymous, is confusing. If you look at the example, the type of the value changes from one version to the next, even though no type is specified.Consider this: enum Foo { x = 'a' } Now we remove Foo: enum { x = 'a' } Now x is a char, where Foo.x was an int? That is very confusing.C, C++, and D already work that way. Such are in common use, and I've not heard a complaint that it is very confusing. For example, it's in std.c.windows.windows.d (among many), and there's not been a single comment on it (pro or con) in 6 years in this n.g.Extending it to allow heterogeneous types is not a big step, nor does it break any existing code or usage.Just because you can do something that changes the meaning of a keyword, especially to a meaning that is not described well by the english meaning of the word, and still have existing code compile, doesn't mean you should. Having heterogeneous types in the same enum braces is a big step, because it fundamentally says 'enum is not an enumeration'. -Steve
Dec 28 2007
Steven Schveighoffer wrote:You missed the point of my example :) I'm not debating anonymous enumerations and whether they should exist or not. I'm saying that the definition of enum working like an enumeration, or working like a manifest list, based on whether the enumeration is named or anonymous, is confusing. If you look at the example, the type of the value changes from one version to the next, even though no type is specified.That's a good point.It doesn't mean you shouldn't, either. This goes on all the time in programming languages. After all, ! doesn't mean exclamation. The reason we even have to invent programming languages is because english is too imprecise and ambiguous. If anyone tries to learn programming by using Webster's, they're in for some pretty tough sledding :-) That said, I would still shrink from using an utterly contradictory meaning, like having the keyword "and" actually do an "or", but there isn't that problem here.Extending it to allow heterogeneous types is not a big step, nor does it break any existing code or usage.Just because you can do something that changes the meaning of a keyword, especially to a meaning that is not described well by the english meaning of the word, and still have existing code compile, doesn't mean you should.Having heterogeneous types in the same enum braces is a big step, because it fundamentally says 'enum is not an enumeration'.I don't see any fundamental reason why an enumeration's contents must all be the same type. You could convincingly argue that they all must be somehow related to each other, but that doesn't require they be related by type. Grouping semantically related ones together would be the purview of the programmer.
Dec 28 2007
Walter Bright wrote:Steven Schveighoffer wrote:No, they don't. In C, x has integral type, whether the enum is named or not. In C++, x is *not* an int, but rather its type is an enum type (named or not). Naming the enum type does not affect the type of x in C or C++. (The fact that C says that 'a' is an int and C++ says that it is a char is a separate issue.)Consider this: enum Foo { x = 'a' } Now we remove Foo: enum { x = 'a' } Now x is a char, where Foo.x was an int? That is very confusing.C, C++, and D already work that way.Such are in common use, and I've not heard a complaint that it is very confusing.It apparently confuses D's designer -- what chance do us mere mortals have?! -- James
Dec 28 2007
James Dennett wrote:No, they don't.You're right, I should have gone back and checked the spec.
Dec 28 2007
On Fri, 28 Dec 2007 12:26:53 -0800, Walter Bright wrote:Steven Schveighoffer wrote:So in short, 'enum' no longer stands for 'enumeration'. -- Derek Parnell Melbourne, Australia skype: derek.j.parnellThis is going to confuse the hell out of all newcomers, and I think there are very few people who use D that actually think this is a good idea (myself included). There are much better ways to solve this problem than destroying the traditional meaning of enum.I understand your point, but also consider that adding yet a fourth way to declare constants is not going to be illuminating for newcomers, and it makes D look like a mishmash. Furthermore, it does not destroy the meaning of enum. Already, you can do this in C, C++ and D: enum { x = 1, y = 2 } // x and y are int's we just extend it a bit so that they don't have to be all the same type: enum { x = 1, y = 2L } // x is int, y is long and allow the { } to be dropped if only one declaration is present. We also drop the requirement that enum types be only integral ones.
Dec 28 2007
Walter Bright wrote:Jérôme M. Berger wrote:This statement really disturbs me, as this is clearly a major change to an enum. I think the consequences are quite horrible. The primary function of enum is to create a TYPE based on a GROUP of related INTEGRAL constants. You can abuse the facility to declare integral constants, but that's a secondary feature at best. The problem is that using enum for abtritrary types is a very poor match for the primary feature of enums. We don't want to create a type; we don't want a grouping; and the values are not integral. enum : int { A=2, B, C } Having an enum automatically get the 'next' value is one of the key feature of enums, and it relies on the base type being an enumerable type. char [], structs, and floating-point types don't have that behaviour. You're guaranteed that integral types remain as a special case. In another post, you mentioned that this would become allowed, to reduce the effect of the special case: enum : float { A=2, B, C } Which leads to the same nonsense you get with operator ++ on floats; a++ is not necessarily different to a. I would hope that this feature never actually gets used. Does this compile? enum : cfloat { A=2, B, C } The important point is that you are now trying to minimise the effect of the special case which has been created. But there's no way to get rid of it, because it is fundamental to the nature of enums. AFAICT there's also special cases related to the grouping (named vs unnamed enums) and with regard to the typing (name mangling).:(Yeah, I figure I'll get fricasseed over that one. The most compelling argument is that we already have 3 ways to declare a constant, adding a fourth gets very difficult to justify. As opposed to a minor extension to enums.
Dec 28 2007
On 12/29/07, Don Clugston <dac nospam.com.au> wrote:Does this compile? enum : cfloat { A=2, B, C }Even more interestingly, what about enum : ifloat { a = 2i, b }; If b has to equal (a+1), then there is no way it can be the same type as a.
Dec 29 2007
Janice Caron wrote:On 12/29/07, Don Clugston <dac nospam.com.au> wrote:It would give the same result as: ifloat b = a + 1;Does this compile? enum : cfloat { A=2, B, C }Even more interestingly, what about enum : ifloat { a = 2i, b }; If b has to equal (a+1), then there is no way it can be the same type as a.
Dec 29 2007
On Sat, 29 Dec 2007 08:36:07 -0000, Janice Caron <caron800 googlemail.co= m> = wrote:On 12/29/07, Don Clugston <dac nospam.com.au> wrote:as =Does this compile? enum : cfloat { A=3D2, B, C }Even more interestingly, what about enum : ifloat { a =3D 2i, b }; If b has to equal (a+1), then there is no way it can be the same type =a.I think Doug's arguments are the must compelling yet. However, just to play Devil's advocate with your complaint about proper = = enumerations. What if rather than being +1. The successor operation was always = opIncrement and what if opIncrement could be implemented as a free function extending even built= in = types. E.g. ifloat opIncrement(ifloat this) { return this+1i; } I'm not sure if the conference proposal of using free functions to exten= d = classes went as far as allowing operators to be declared this way but I don't see why= = it shouldn't.
Dec 29 2007
On Sat, 29 Dec 2007 12:34:15 -0000, Bruce Adams = <tortoise_74 yeah.who.co.uk> wrote:On Sat, 29 Dec 2007 08:36:07 -0000, Janice Caron =<caron800 googlemail.com> wrote:=On 12/29/07, Don Clugston <dac nospam.com.au> wrote:Does this compile? enum : cfloat { A=3D2, B, C }Even more interestingly, what about enum : ifloat { a =3D 2i, b }; If b has to equal (a+1), then there is no way it can be the same type=Obviously I meant Don's arguments. Oops. Which by the way is exactly the "enum hack" we were sometimes forced to = = use in C++ before it was sanitised prior to the ISO standard. On 12/29/07, Don Clugston <dac nospam.com.au> wrote: "The primary function of enum is to create a TYPE based on a GROUP of = related INTEGRAL constants. You can abuse the facility to declare integr= al = constants, but that's a secondary feature at best. The problem is that = using enum for abtritrary types is a very poor match for the primary = feature of enums. We don't want to create a type; we don't want a grouping; and the values= = are not integral."as a.I think Doug's arguments are the must compelling yet.
Dec 29 2007
Don Clugston wrote:Walter Bright wrote:It doesn't change existing usage of enum.Jérôme M. Berger wrote:This statement really disturbs me, as this is clearly a major change to an enum.:(Yeah, I figure I'll get fricasseed over that one. The most compelling argument is that we already have 3 ways to declare a constant, adding a fourth gets very difficult to justify. As opposed to a minor extension to enums.I think the consequences are quite horrible. The primary function of enum is to create a TYPE based on a GROUP of related INTEGRAL constants.None of the enhancements impair this.You can abuse the facility to declare integral constants, but that's a secondary feature at best. The problem is that using enum for abtritrary types is a very poor match for the primary feature of enums. We don't want to create a type; we don't want a grouping; and the values are not integral. enum : int { A=2, B, C } Having an enum automatically get the 'next' value is one of the key feature of enums, and it relies on the base type being an enumerable type.The only thing it relies on is the ability to add 1 to the previous value. The new enums can automatically get the next value for any type with this characteristic, including UDT's that overload opAdd, as long as they can be evaluated at compile time.char [], structs, and floating-point types don't have that behaviour.You're right about char[], but structs can have that behavior, and fp types do. This means that: enum Color : string { Red="red", Blue } would not compile, whereas: enum Color : string { Red="red", Blue="blue" } would.You're guaranteed that integral types remain as a special case. In another post, you mentioned that this would become allowed, to reduce the effect of the special case: enum : float { A=2, B, C }The above example would result in A being 2.0f, B being 3.0f, and C being 4.0f.Which leads to the same nonsense you get with operator ++ on floats; a++ is not necessarily different to a. I would hope that this feature never actually gets used.You're right that, for nans, infinity, and very small values, (a+1)==a. But this is an inescapable of reality with fp arithmetic, and we don't disallow fp arithmetic because of it. We could, though, add a check that if the 'next' value doesn't change after being incremented, an error message is produced. There already is an error generated if the value being incremented is equal to the underlying type's .max, which prevents unintended overflows.Does this compile? enum : cfloat { A=2, B, C }Yes. A would be a cfloat with value 2.0+0i, B would be 3.0+0i, C would be 4.0+0i. There isn't a special case, all it does is: (next value)=(previousvalue) + 1 and run it through the usual semantic analysis. I don't know of a cause where one would want to declare complex constants this way, but the aim here is consistency.The important point is that you are now trying to minimise the effect of the special case which has been created. But there's no way to get rid of it, because it is fundamental to the nature of enums.I don't understand exactly what the created special case is you're referring to. The enhanced enums remove the special case that restricted enums to being integral types.AFAICT there's also special cases related to the grouping (named vs unnamed enums) and with regard to the typing (name mangling).Anonymous enums don't have a type (and didn't in D1.0, either). There's no way to get a grip on such a type anyway, as it has no name and: enum { FOO, BAR } x; style declarations are not allowed in D. Let me enumerate (!) the enhancements to enum: 1) The enum 'base type' is no longer restricted to being integral types only. 2) Members of anonymous enums can now be of heterogeneous types, the types being deduced from their initializers. 3) .init, .min and .max have no meaning for anonymous enums, and so are computed only for tagged enums. 4) For anonymous enum members, a type can prefix the identifier as a convenience. 5) If there is only one member in an anonymous enum, the { } can be omitted. 6) If .init, .min, .max or 'next' values are not required, then the base type doesn't have to support the operations required to produce those values. None of these are takeaways.
Dec 29 2007
Why not keeping enum as it was and use manfifest as enhanced enum ? Seems to be a clean solution. Bjoern
Dec 29 2007
BLS wrote:Why not keeping enum as it was and use manfifest as enhanced enum ? Seems to be a clean solution.Because, then there's a fourth way to declare constants. 3 seems to be enough.
Dec 29 2007
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Walter Bright wrote:BLS wrote:You are already adding a fourth way to declare constants. In fact, I believe the "enum hack" way of declaring constants should be deprecated and only kept around for backward compatibility and new code should use "manifest" (or whatever new keyword). Jerome - -- +------------------------- Jerome M. BERGER ---------------------+ | mailto:jeberger free.fr | ICQ: 238062172 | | http://jeberger.free.fr/ | Jabber: jeberger jabber.fr | +---------------------------------+------------------------------+ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) iD8DBQFHdmFud0kWM4JG3k8RAihuAKCwAbFRPUSDCEOdi9r+GoO0BtESZQCgjH3B sfSgIzCAQEYCQvCfkw5tzG4= =4XdK -----END PGP SIGNATURE-----Why not keeping enum as it was and use manfifest as enhanced enum ? Seems to be a clean solution.Because, then there's a fourth way to declare constants. 3 seems to be enough.
Dec 29 2007
On Sat, 29 Dec 2007 02:00:26 -0800, Walter Bright wrote:BLS wrote:I think the distinction comes down to adding another keyword, not a fourth way (which, as others mention, is happening nonetheless). I know you try very hard to avoid adding more keywords to D. It's always been that way and will always be that way. So I guess the contention is (and will always be) * whether it's worth the clarity that yet-another-keyword offers (YAK, for short :) ) * whether more overloading of type semantics makes sense (how much longer can D handle this) The manifest constant is really quite different from the other semantics of constant; and I think that it deserves to be set apart from the rest as a completely different entity (afterall this used to be achieved by something like #define's in C/C++). But then, I'm not sure if you have set goals on how many keywords you're allowed to add per year. If you have some sort of limit, I can see how you necessarily must show restraint. :) My question is: at what point do D keywords reach critical mass (in terms of keyword hijacking for new functionality)? This seems to happen repeatedly as D struggles to avoid keyword additions... at what /appears/ to be the expense of the programmer. This new manifest enum could work and eventually people might just get used to it... but it's so strange, so foreign, and so seemingly inconsistant that I think your betting heavily on the good-graces of your d community (who likely will forgive you and move on). But I do wonder if this is the case for all those users that are still deciding whether to adopt D or not. D 2.0 is an indicator of what is to come... so decisions made here are going to speak volumes about the future. I don't know how newcomers would react or what confusion it would cause novices, so I won't use that as argument against it. But it's a gamble and a seemingly very risky gamble. Some would say high-risk gambles don't make sense, especially when the payback is nominal. -JJRWhy not keeping enum as it was and use manfifest as enhanced enum ? Seems to be a clean solution.Because, then there's a fourth way to declare constants. 3 seems to be enough.
Dec 29 2007
John Reimer wrote:The manifest constant is really quite different from the other semantics of constant;The previous problems we were having with the design of the const system all seemed to revolve, one way or another, around trying to accommodate two different kinds of constants with one scheme. Separating the two, i.e. the notion of "manifest constant" from "constant type", seems to finally allow things to work.and I think that it deserves to be set apart from the rest as a completely different entity (afterall this used to be achieved by something like #define's in C/C++).Yes.But then, I'm not sure if you have set goals on how many keywords you're allowed to add per year. If you have some sort of limit, I can see how you necessarily must show restraint. :)As I remarked elsewhere, there is no language design problem that cannot be resolved by adding more keywords. Just like with aircraft design, there is no problem that cannot be fixed by adding more thrust <g>. D already has quite a lot of keywords. Trying to stem the flood if possible is a reasonable goal.My question is: at what point do D keywords reach critical mass (in terms of keyword hijacking for new functionality)? This seems to happen repeatedly as D struggles to avoid keyword additions... at what /appears/ to be the expense of the programmer.As I suggested, all the enum enhancements do is remove restrictions placed on its use. I don't see how that is costing the programmer.This new manifest enum could work and eventually people might just get used to it... but it's so strange, so foreign, and so seemingly inconsistant that I think your betting heavily on the good-graces of your d community (who likely will forgive you and move on).I think it'll seem strange for about 5 minutes, and then will seem normal. After all, that's what happened with the !( ) syntax for templates rather than < >.But I do wonder if this is the case for all those users that are still deciding whether to adopt D or not. D 2.0 is an indicator of what is to come... so decisions made here are going to speak volumes about the future. I don't know how newcomers would react or what confusion it would cause novices, so I won't use that as argument against it. But it's a gamble and a seemingly very risky gamble. Some would say high-risk gambles don't make sense, especially when the payback is nominal.I would argue it is less confusing than introducing yet another keyword, especially a keyword whose usage overlaps 3 other keywords, but only time will tell.
Dec 29 2007
Walter Bright wrote:LOL! That's a good analogy... :) Although, there's probably an equally astute analogy pointing out the the shortcomings of re-using keywords. ;) But I still like what you say here.But then, I'm not sure if you have set goals on how many keywords you're allowed to add per year. If you have some sort of limit, I can see how you necessarily must show restraint. :)As I remarked elsewhere, there is no language design problem that cannot be resolved by adding more keywords. Just like with aircraft design, there is no problem that cannot be fixed by adding more thrust <g>.D already has quite a lot of keywords. Trying to stem the flood if possible is a reasonable goal.Agreed.I guess that's to be found out.My question is: at what point do D keywords reach critical mass (in terms of keyword hijacking for new functionality)? This seems to happen repeatedly as D struggles to avoid keyword additions... at what /appears/ to be the expense of the programmer.As I suggested, all the enum enhancements do is remove restrictions placed on its use. I don't see how that is costing the programmer.I hate to be a pushover on this one <g>, but I'll just accept this enum thing and hope for the best.This new manifest enum could work and eventually people might just get used to it... but it's so strange, so foreign, and so seemingly inconsistant that I think your betting heavily on the good-graces of your d community (who likely will forgive you and move on).I think it'll seem strange for about 5 minutes, and then will seem normal. After all, that's what happened with the !( ) syntax for templates rather than < >.I think this is the whole source of the disagreement. A number of us were arguing that we think this is more confusing... but I think we'll survive. -JJRBut I do wonder if this is the case for all those users that are still deciding whether to adopt D or not. D 2.0 is an indicator of what is to come... so decisions made here are going to speak volumes about the future. I don't know how newcomers would react or what confusion it would cause novices, so I won't use that as argument against it. But it's a gamble and a seemingly very risky gamble. Some would say high-risk gambles don't make sense, especially when the payback is nominal.I would argue it is less confusing than introducing yet another keyword, especially a keyword whose usage overlaps 3 other keywords, but only time will tell.
Dec 29 2007
John Reimer wrote:I think this is the whole source of the disagreement. A number of us were arguing that we think this is more confusing... but I think we'll survive.Of course we will, but it is yet another feature that will build annoyance (no, I doubt it will go over after 5 minutes), and with a young language that you want to have a broader exposure, it is very unnecessary to choose the annoying (bad) solution. -- Lars Ivar Igesund blog at http://larsivi.net DSource, #d.tango & #D: larsivi Dancing the Tango
Dec 30 2007
Walter Bright schrieb:BLS wrote:In case that you can use a keyword in 4 different ways this will increase the change for wrong use to exactly 300 percent ;-) I agree with Bill B;, who mentioned in another thread that the number of keywords is not nessesarly an indicator for a complex language. BjoernWhy not keeping enum as it was and use manfifest as enhanced enum ? Seems to be a clean solution.Because, then there's a fourth way to declare constants. 3 seems to be enough.
Dec 30 2007
On Sat, 29 Dec 2007 08:59:46 -0000, Walter Bright = <newshound1 digitalmars.com> wrote:Let me enumerate (!) the enhancements to enum: 1) The enum 'base type' is no longer restricted to being integral type=s =only. 2) Members of anonymous enums can now be of heterogeneous types, the =types being deduced from their initializers. 3) .init, .min and .max have no meaning for anonymous enums, and so ar=e =computed only for tagged enums. 4) For anonymous enum members, a type can prefix the identifier as a =convenience. 5) If there is only one member in an anonymous enum, the { } can be =omitted. 6) If .init, .min, .max or 'next' values are not required, then the ba=se =type doesn't have to support the operations required to produce those ==values. None of these are takeaways.Personally I always name my types but there may be those that don't. Is this currently illegal then? class Colour { private: // private helper type defining colour state variable // using an anonymous enum. enum { red, green, blue } colour; };Don Clugston wrote:=Having an enum automatically get the 'next' value is one of the key ==feature of enums, and it relies on the base type being an enumerable =type.The only thing it relies on is the ability to add 1 to the previous =value. The new enums can automatically get the next value for any type==with this characteristic, including UDT's that overload opAdd, as long==as they can be evaluated at compile time.Why opAdd and not opIncrement? opAdd(int) seems unnatural for user defined types. They would have to = ignore the argument and it would lead to some odd bugs and confusions. Very contrived and poorly chosen example: class Foo { public: // helper type enum FooType { A =3D "foo", B =3D "bar", C =3D "snafu" } private: // state - bar may be one o string Bar; public: Foo() { Bar =3D A; } // only used to allow creation of Foo based enums. Foo opAdd(int) { Bar++; } } enum FooBar: Foo { A =3D Foo("foo"), B =3D Foo("bar"), C =3D Foo("snafu") } FooBar a =3D FooBar.A; FooBar b =3D FooBar.B; FooBar c =3D FooBar.C; assert(b =3D=3D (a+1)); // okay assert(c =3D=3D (b+1)); // okay assert(b =3D=3D (a+2)); // surprising!
Dec 29 2007
On 12/29/07, Bruce Adams <tortoise_74 yeah.who.co.uk> wrote:Why opAdd and not opIncrement?There is no opIncrement(). There's only opPostInc(), which requires that its input be an lvalue. Note that (x++) evaluates to x, not to x+1 (but x itself will be incremented). For rvalues, opAdd() is all you have. In /real/ enumerations, the successor is (by definition) the next item in the list. That is, given the enumeration { r, o, y, g, b, i v }, the successor of r is o, the successor of o is y, and so on, and this will be true regardless of the underlying implementation (which the application should neither know nor care). Of course, C, C++ and D enums are not true enumerations, and we don't have successor nor predecessor functions. The "trick" of figuring out a default implementation value for the next element is just that.
Dec 29 2007
Bruce Adams wrote:Personally I always name my types but there may be those that don't. Is this currently illegal then? class Colour { private: // private helper type defining colour state variable // using an anonymous enum. enum { red, green, blue } colour; };Yes, it is illegal.Why opAdd and not opIncrement?opIncrement is redundant, as it's a subset of opAdd.opAdd(int) seems unnatural for user defined types. They would have to ignore the argument and it would lead to some odd bugs and confusions.I don't know why it would be unnatural. To me, a type that can be incremented but not added would seem very strange indeed.Very contrived and poorly chosen example: class Foo { public: // helper type enum FooType { A = "foo", B = "bar", C = "snafu" } private: // state - bar may be one o string Bar; public: Foo() { Bar = A; } // only used to allow creation of Foo based enums. Foo opAdd(int) { Bar++;A string cannot be incremented.} } enum FooBar: Foo { A = Foo("foo"), B = Foo("bar"), C = Foo("snafu") } FooBar a = FooBar.A; FooBar b = FooBar.B; FooBar c = FooBar.C; assert(b == (a+1)); // okay assert(c == (b+1)); // okay assert(b == (a+2)); // surprising!
Dec 29 2007
On Sun, 30 Dec 2007 01:47:03 -0000, Walter Bright = <newshound1 digitalmars.com> wrote:Bruce Adams wrote:No problem there then.Personally I always name my types but there may be those that don't. Is this currently illegal then? class Colour { private: // private helper type defining colour state variable // using an anonymous enum. enum { red, green, blue } colour; };Yes, it is illegal.=Why opAdd and not opIncrement?opIncrement is redundant, as it's a subset of opAdd.opAdd(int) seems unnatural for user defined types. They would have to=ignore the argument and it would lead to some odd bugs and confusions.I don't know why it would be unnatural. To me, a type that can be =incremented but not added would seem very strange indeed.Surely that is what we mean with an enumeration. We allow successor (and= = optionally predecessor) operations to cycle through the entities in a particular order but addin= g = them is unnatural. Granted you can use a sucessor operation to define addition that's the = typical way number theory is derived from set theory but we are talking about programmers who can = = make errors. enum Colour { red, green, blue, indigo } Colour c =3D red; c++; // c =3D blue Colour c2 =3D red+green; //a bad thing to allow.I said it was poorly chosen :-). All I'm saying is a programmer might be= = tempted to defined opAdd with the semantics of an increment operation if they only = = wanted this behaviour at all to allow them to define enumerations with a = different successor operation. Here is another less poor but still non-optimal example. class OddNumbers { // helper type typedef int FooType; // state FooType bar; Foo() { bar =3D 1; } // bad semantics - hacked to value OddEnum as required. Foo opAdd(int) { bar +=3D 2; } } enum OddEnum: OddNumbers { one =3D 1, three, // =3D=3D 3 five // =3D=3D 5 } This is not a brilliant example as it is sensible to have a genuine = addition operator for odd numbers but for many types you could be defining opAdd(int) for = = this purpose when int is not sensibly addable to the class itself.Very contrived and poorly chosen example: class Foo { public: // helper type enum FooType { A =3D "foo", B =3D "bar", C =3D "snafu" } private: // state - bar may be one o string Bar; public: Foo() { Bar =3D A; } // only used to allow creation of Foo based enums. Foo opAdd(int) { Bar++;A string cannot be incremented.
Dec 29 2007
On 12/30/07, Bruce Adams <tortoise_74 yeah.who.co.uk> wrote:Surely that is what we mean with an enumeration. We allow successor (and optionally predecessor) operations to cycle through the entities in a particular order but adding them is unnatural.In a true enumeration, it isn't that unreasonable to equate ++ or +1 with the successor function, and -- or -1 with the predecessor function. Given that, for an enum type E, what you want to allow is E opAdd(int) E opSub(int) but you want to disallow E opAdd(E) E opSub(E) So to use your example: Colour c2 = red+green; //WRONG Colour c2 = red+2; //OK the latter meaning the successor of the successor. Of course D enums aren't true enums, so we might end up having to allow "red+green" by accident. :-)
Dec 29 2007
On Sun, 30 Dec 2007 03:41:40 -0000, Janice Caron <caron800 googlemail.co= m> = wrote:On 12/30/07, Bruce Adams <tortoise_74 yeah.who.co.uk> wrote:andSurely that is what we mean with an enumeration. We allow successor (=optionally predecessor) operations to cycle through the entities in a particular order but =Which is a bad thing. I would also like the option to prevent red+2 at compile time. Its not going to be terribly helpful to pick up an out of range error if= someone foolishly adds an integer that takes the value out of the permit= ted range for the type. enumeraitons are not closed under addition. Okay fix= ed = length binary integers aren't either but they are less closed and have well = defined if often undesireable overflow semantics.adding them is unnatural.In a true enumeration, it isn't that unreasonable to equate ++ or +1 with the successor function, and -- or -1 with the predecessor function. Given that, for an enum type E, what you want to allow is E opAdd(int) E opSub(int) but you want to disallow E opAdd(E) E opSub(E) So to use your example: Colour c2 =3D red+green; //WRONG Colour c2 =3D red+2; //OK the latter meaning the successor of the successor. Of course D enums aren't true enums, so we might end up having to allow "red+green" by accident. :-)
Dec 29 2007
Walter Bright wrote:Bruce Adams wrote:Except if you care about efficiency, in which case you might well have types which admit an efficient (constant time) increment but not a constant-time addition in general. (Contiguous enumerated types should not have that issue, however, nor should any type which has an underlying integral representation.) -- JamesPersonally I always name my types but there may be those that don't. Is this currently illegal then? class Colour { private: // private helper type defining colour state variable // using an anonymous enum. enum { red, green, blue } colour; };Yes, it is illegal.Why opAdd and not opIncrement?opIncrement is redundant, as it's a subset of opAdd.
Dec 29 2007
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Walter Bright wrote:Don Clugston wrote:Yes an no: sure, existing code will still compile and work. However, it confuses things for the programmer. Enums used to have a clearly delimited function: creating a type based on a group of related items (the fact that it is implemented as an integral type should have remained an implementation detail IMO). The fact that enums may be used (or abused) otherwise is more a misfeature which allowed the programmer to work around some language limitations. I'm all in favor of removing those limitations and I understand keeping the old enum behavior around for compatibility reasons, but extending the "enum hack" is not the way to do it. In other words: some current usages of enum are a hack to work around some language limitations. Those usages should be deprecated in favor of another keyword that would allow them plus extra functionality (e.g. manifest constants) while "enum" is relegated to its proper usage. I believe anything else would be too confusing (particularly to newcomers). Jerome - -- +------------------------- Jerome M. BERGER ---------------------+ | mailto:jeberger free.fr | ICQ: 238062172 | | http://jeberger.free.fr/ | Jabber: jeberger jabber.fr | +---------------------------------+------------------------------+ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) iD8DBQFHdmBVd0kWM4JG3k8RAlzPAJ0QKHazsbtH3oheKMnKIccvjBAihACfUDhQ qQK9A0r3FjLE4WYp6mR9CJc= =sXTi -----END PGP SIGNATURE-----Walter Bright wrote:It doesn't change existing usage of enum.Jérôme M. Berger wrote:This statement really disturbs me, as this is clearly a major change to an enum.:(Yeah, I figure I'll get fricasseed over that one. The most compelling argument is that we already have 3 ways to declare a constant, adding a fourth gets very difficult to justify. As opposed to a minor extension to enums.
Dec 29 2007
On 12/29/07, "Jérôme M. Berger" <jeberger free.fr> wrote:Those usages should be deprecated in favor of another keyword that would allow them plus extra functionality (e.g. manifest constants) while "enum" is relegated to its proper usage. I believe anything else would be too confusing (particularly to newcomers).It would be /really/ cool if Walter just implemented everything as he suggested, except for deprecating the word "enum" and replacing it with "manifest" everywhere. Then "enum" could be redeployed for true enumerations only. e.g. enum Primary { red, blue, green } Primary col = red; int x = col; /* ERROR */ int x = cast(int)col /* STILL AN ERROR */ col = 1; /* ALSO AN ERROR */ col = cast(Primary)1; /* NOPE! */ Primary col2 = col++; /* successor */ assert(col2 = Primary.blue); if (col == col2) { /*...*/ } if (col < col2) { /*...*/ } enum { x = 2 }; /* ERROR */ enum E { x = 2 }; /* ERROR */ enum E : int { x }; /* ERROR */ ...but it will never happen! (Sigh!)
Dec 29 2007
Janice Caron wrote:On 12/29/07, "Jérôme M. Berger" <jeberger free.fr> wrote:Yes, please!Those usages should be deprecated in favor of another keyword that would allow them plus extra functionality (e.g. manifest constants) while "enum" is relegated to its proper usage. I believe anything else would be too confusing (particularly to newcomers).It would be /really/ cool if Walter just implemented everything as he suggested, except for deprecating the word "enum" and replacing it with "manifest" everywhere."manifest", if not "define" (my preference) or "pure".Then "enum" could be redeployed for true enumerations only. e.g. enum Primary { red, blue, green } Primary col = red; int x = col; /* ERROR */ int x = cast(int)col /* STILL AN ERROR */ col = 1; /* ALSO AN ERROR */ col = cast(Primary)1; /* NOPE! */ Primary col2 = col++; /* successor */ assert(col2 = Primary.blue); if (col == col2) { /*...*/ } if (col < col2) { /*...*/ } enum { x = 2 }; /* ERROR */ enum E { x = 2 }; /* ERROR */ enum E : int { x }; /* ERROR */ ...but it will never happen! (Sigh!)Why not? It will break existing code, but given the length of these threads, D users may be prepared to cope with it where it does... Bastiaan.
Dec 29 2007
"Walter Bright" wroteDon Clugston wrote:Correct me if I'm wrong, but isn't opAdd disallowed at compile time because it uses a this pointer? Or are you changing that behavior for this feature? -SteveYou can abuse the facility to declare integral constants, but that's a secondary feature at best. The problem is that using enum for abtritrary types is a very poor match for the primary feature of enums. We don't want to create a type; we don't want a grouping; and the values are not integral. enum : int { A=2, B, C } Having an enum automatically get the 'next' value is one of the key feature of enums, and it relies on the base type being an enumerable type.The only thing it relies on is the ability to add 1 to the previous value. The new enums can automatically get the next value for any type with this characteristic, including UDT's that overload opAdd, as long as they can be evaluated at compile time.
Dec 29 2007
Steven Schveighoffer wrote:Correct me if I'm wrong, but isn't opAdd disallowed at compile time because it uses a this pointer? Or are you changing that behavior for this feature?You're quite right. But I do intend to eventually extend CTFE to get this to work. I think CTFE is only just starting to show its potential.
Dec 29 2007
Walter Bright wrote:Let me enumerate (!) the enhancements to enum: 1) The enum 'base type' is no longer restricted to being integral types only. 2) Members of anonymous enums can now be of heterogeneous types, the types being deduced from their initializers. 3) .init, .min and .max have no meaning for anonymous enums, and so are computed only for tagged enums. 4) For anonymous enum members, a type can prefix the identifier as a convenience. 5) If there is only one member in an anonymous enum, the { } can be omitted. 6) If .init, .min, .max or 'next' values are not required, then the base type doesn't have to support the operations required to produce those values.You can regard me as a newcomer. In my view, enums are often used in support of switch statements. If you are loosening up enums so its members can be of heterogeneous types, will you be loosening up switch/case as well? If not, that would be confusing to me, as you will be able to switch on some enums but not on others. Sincerely, Bastiaan.
Dec 30 2007
On 12/30/07, Bastiaan Veelo <Bastiaan veelo.net> wrote:If not, that would be confusing to me, as you will be able to switch on some enums but not on others.You can't switch on an anonymous enum. Anonymous enums have no type, and therefore it is not even /possible/ to generate an expression whose type is that of an anonymous enum! So switch/case survives unharmed.
Dec 30 2007
On Sun, 30 Dec 2007 11:27:17 +0000, Janice Caron wrote:On 12/30/07, Bastiaan Veelo <Bastiaan veelo.net> wrote:And yet this compiles and runs ... // ------------- import std.stdio; enum { one = 1, two = 2, three = 3 } void main() { auto x = three; switch (x) { case one: writefln("ONE"); break; case two: writefln("TWO"); break; case three: writefln("THREE"); break; } } // ------------- -- Derek Parnell Melbourne, Australia skype: derek.j.parnellIf not, that would be confusing to me, as you will be able to switch on some enums but not on others.You can't switch on an anonymous enum. Anonymous enums have no type, and therefore it is not even /possible/ to generate an expression whose type is that of an anonymous enum! So switch/case survives unharmed.
Dec 30 2007
Derek Parnell wrote:On Sun, 30 Dec 2007 11:27:17 +0000, Janice Caron wrote:And I'd have been surprised if not... if it was called "manifest", would anyone at all get the idea that you can't case against them, because they are something oh so entirely different from a literal number? Ooops, wait... wasn't it supposed to be just like one? =) regards, frank --- Making a statement bold and confident doesn't make it true.On 12/30/07, Bastiaan Veelo <Bastiaan veelo.net> wrote:And yet this compiles and runs ... [source: switch with anon enum]If not, that would be confusing to me, as you will be able to switch on some enums but not on others.You can't switch on an anonymous enum. Anonymous enums have no type, and therefore it is not even /possible/ to generate an expression whose type is that of an anonymous enum! So switch/case survives unharmed.
Dec 30 2007
Derek Parnell wrote:On Sun, 30 Dec 2007 11:27:17 +0000, Janice Caron wrote:Yes, and although the extended enum would allow three to be defined as 3f, then case three would not compile according to the current spec. That is obvious in this example, but it is a confusing inconsistency in the relation between enum and switch. enum and switch have always been compatible in my mind, but that is about to change... Bastaan.On 12/30/07, Bastiaan Veelo <Bastiaan veelo.net> wrote:And yet this compiles and runs ... // ------------- import std.stdio; enum { one = 1, two = 2, three = 3 } void main() { auto x = three; switch (x) { case one: writefln("ONE"); break; case two: writefln("TWO"); break; case three: writefln("THREE"); break; } } // -------------If not, that would be confusing to me, as you will be able to switch on some enums but not on others.You can't switch on an anonymous enum. Anonymous enums have no type, and therefore it is not even /possible/ to generate an expression whose type is that of an anonymous enum! So switch/case survives unharmed.
Dec 30 2007
Derek Parnell wrote:On Sun, 30 Dec 2007 11:27:17 +0000, Janice Caron wrote:Yes, and x is of type int, not anonymous enum.On 12/30/07, Bastiaan Veelo <Bastiaan veelo.net> wrote:And yet this compiles and runs ... // ------------- import std.stdio; enum { one = 1, two = 2, three = 3 } void main() { auto x = three; switch (x) { case one: writefln("ONE"); break; case two: writefln("TWO"); break; case three: writefln("THREE"); break; } }If not, that would be confusing to me, as you will be able to switch on some enums but not on others.You can't switch on an anonymous enum. Anonymous enums have no type, and therefore it is not even /possible/ to generate an expression whose type is that of an anonymous enum! So switch/case survives unharmed.
Dec 30 2007
On 12/30/07, Janice Caron <caron800 googlemail.com> wrote:You can't switch on an anonymous enum. Anonymous enums have no type, and therefore it is not even /possible/ to generate an expression whose type is that of an anonymous enum! So switch/case survives unharmed.OK, so everyone pointed out I got that wrong. Thanks, guys. What I meant was: you can't switch on a heterogenous anonymous enum, because heterogenous anonymous enums have no type. Sorry for the confusion.
Dec 30 2007
Janice Caron wrote:What I meant was: you can't switch on a heterogenous anonymous enum, because heterogenous anonymous enums have no type.with enum { int one = 1; float two = 2.0; string three = "three"; } I'd expect void foo(int x) { switch (x) { case one: writefln("ONE"); break; // this should be legal case two: writefln("TWO"); break; // but not this case three: writefln("THREE"); break; // much less this } } because to me the rule "case guards can only be of integral type" seems to make the most sense. I'd be rather disappointed if case one didn't work... regards, frank
Dec 30 2007
0ffh wrote:enum { int one = 1; float two = 2.0; string three = "three"; }Ooops, I suppose there should be commas here not semicolons... regards, frank
Dec 30 2007
0ffh wrote:because to me the rule "case guards can only be of integral type" seems to make the most sense. I'd be rather disappointed if case one didn't work...Actually, D also allows string switch. However, I'm pretty sure you can't mix int "switch" with string "case"s :P. Spec reference: http://www.digitalmars.com/d/1.0/statement.html#SwitchStatement --- /Expression/ is evaluated. The result type T must be of integral type or char[], wchar[] or dchar[]. The result is compared against each of the case expressions. If there is a match, the corresponding case statement is transferred to. ---
Dec 30 2007
Frits van Bommel wrote:0ffh wrote:Hmmm, that's rather... cool. :) You live and learn. regards, frankbecause to me the rule "case guards can only be of integral type" seems to make the most sense. I'd be rather disappointed if case one didn't work...Actually, D also allows string switch. However, I'm pretty sure you can't mix int "switch" with string "case"s :P.
Dec 30 2007
On 12/30/07, 0ffh <frank youknow.what.todo.internetz> wrote:because to me the rule "case guards can only be of integral type" seems to make the most sense. I'd be rather disappointed if case one didn't work...This bit of conversation seems to have lost track of the original point, which, to remind all, was that Bastiaan Veelo said:You can regard me as a newcomer. In my view, enums are often used in support of switch statements. If you are loosening up enums so its members can be of heterogeneous types, will you be loosening up switch/case as well? If not, that would be confusing to me, as you will be able to switch on some enums but not on others.So, the answer is that anonymous enums don't create new types. The type is simply the underlying type. In the case of heterogenous anonymous enums, the type of each element can be different. This is a very different kettle of fish from /named/ enums, which do, in fact, create a new type, allowing the compiler to look at code like enum Primary { red, green, blue } Primary x = whatever; switch (x) { case Primary.red: /*...*/ case Primary.green: /*...*/ } and detect that case blue is missing, and hence a default is needed. It cannot do that for anonymous enums, because it has no way to figure out what the complete set should be. At least, I /think/ that's what Bastiaan was getting at. Anyway, the point is that the new extensions make no difference to switch/case.
Dec 30 2007
Janice Caron wrote:On 12/30/07, 0ffh <frank youknow.what.todo.internetz> wrote:Thank you for reminding me of the proper way of switching on enums. And you are right of course, no difference here. Bastiaan.because to me the rule "case guards can only be of integral type" seems to make the most sense. I'd be rather disappointed if case one didn't work...This bit of conversation seems to have lost track of the original point, which, to remind all, was that Bastiaan Veelo said:You can regard me as a newcomer. In my view, enums are often used in support of switch statements. If you are loosening up enums so its members can be of heterogeneous types, will you be loosening up switch/case as well? If not, that would be confusing to me, as you will be able to switch on some enums but not on others.So, the answer is that anonymous enums don't create new types. The type is simply the underlying type. In the case of heterogenous anonymous enums, the type of each element can be different. This is a very different kettle of fish from /named/ enums, which do, in fact, create a new type, allowing the compiler to look at code like enum Primary { red, green, blue } Primary x = whatever; switch (x) { case Primary.red: /*...*/ case Primary.green: /*...*/ } and detect that case blue is missing, and hence a default is needed. It cannot do that for anonymous enums, because it has no way to figure out what the complete set should be. At least, I /think/ that's what Bastiaan was getting at. Anyway, the point is that the new extensions make no difference to switch/case.
Dec 30 2007
Bastiaan Veelo wrote:You can regard me as a newcomer. In my view, enums are often used in support of switch statements. If you are loosening up enums so its members can be of heterogeneous types, will you be loosening up switch/case as well? If not, that would be confusing to me, as you will be able to switch on some enums but not on others.The heterogeneous types for enums would only be for anonymous enums. I don't think it would make much sense to support case statements of different types, as the switched value is necessarily of only one type.
Dec 30 2007
Walter Bright wrote:Anonymous enums don't have a type (and didn't in D1.0, either). There's no way to get a grip on such a type anyway, as it has no name and: enum { FOO, BAR } x; style declarations are not allowed in D.Now I'm confused. I thought an anonymous enum was an enum without a name. But it is entirely possible to create an anonymous enum with a type, for example: enum : uint {red, green, blue} At least I use that kind of enums a lot and I allways thought of these as anonymous enums. I call enums without a type "typeless enums". LLAP, Sascha Katzner
Dec 30 2007
Sascha Katzner wrote:Walter Bright wrote:I meant that: enum { FOO, BAR } x; is not allowed because enum{FOO,BAR} is not a type declarator. This isn't allowed either: enum ABC { FOO, BAR } x; while: enum ABC { FOO, BAR } ABC x; is allowed.Anonymous enums don't have a type (and didn't in D1.0, either). There's no way to get a grip on such a type anyway, as it has no name and: enum { FOO, BAR } x; style declarations are not allowed in D.Now I'm confused. I thought an anonymous enum was an enum without a name. But it is entirely possible to create an anonymous enum with a type, for example: enum : uint {red, green, blue} At least I use that kind of enums a lot and I allways thought of these as anonymous enums.
Dec 30 2007
On Fri, 28 Dec 2007 01:36:30 -0800, Walter Bright wrote:Jérôme M. Berger wrote:I hate to jump in so late to this already very discussed issue, but I'm going to have to add my voice to those against it. I came to D from C/C++. If someone told me that D replaces #define with enum, I would have laughed in disbelief and then tried to define a bunch of 'static invariant' variables instead. It just seems so counter- intuitive to use enum. I should also add that more keywords is hardly a bad thing. Perl uses a quite large amount of keywords and nobody minds, because each keyword is generally given a meaningful name and a useful purpose. For example in my recent perl script I have the following line::(Yeah, I figure I'll get fricasseed over that one. The most compelling argument is that we already have 3 ways to declare a constant, adding a fourth gets very difficult to justify. As opposed to a minor extension to enums."print "Couldn't get $url\n" and return undef unless defined $content;"Six keywords on one line, and you could hardly say it looks confusing or ugly. I couldn't say the same thing for using enum to define static constants. Please reconsider manifest, Walter. :(
Jan 02 2008
On Fri, 28 Dec 2007 16:15:47 +0900, Bill Baxter wrote:Timestamp: 12/27/07 20:47:21 (5 hours ago) Author: walter Message: manifest => enum http://www.dsource.org/projects/phobos/changeset/536 --bbI'm reminded of a Coca-Cola bottle falling from the sky. -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
Dec 28 2007
Derek Parnell wrote:On Fri, 28 Dec 2007 16:15:47 +0900, Bill Baxter wrote:And we represent all the pygmies sitting in a circle, glumly looking at the "enum"? :) -JJRTimestamp: 12/27/07 20:47:21 (5 hours ago) Author: walter Message: manifest => enum http://www.dsource.org/projects/phobos/changeset/536 --bbI'm reminded of a Coca-Cola bottle falling from the sky.
Dec 28 2007
Bill Baxter wrote:http://www.dsource.org/projects/phobos/changeset/536Good work. I may be in minority, but I think this is a good choice.
Dec 28 2007
Bill Baxter Wrote:Timestamp: 12/27/07 20:47:21 (5 hours ago) Author: walter Message: manifest => enum http://www.dsource.org/projects/phobos/changeset/536 --bbMy only concern with enum is, will people use it? In C++, using enum to define integral constants is actually the closest match to a #DEFINE. However most people use "const int", I guess either because the syntax is more convenient, it's easier to remember or because they don't know any better.
Dec 28 2007
Derek Parnell Wrote:On Fri, 28 Dec 2007 10:35:38 -0800, Walter Bright wrote:You'll be able to doSean Kelly wrote:Will your syntax allow declarations of single values? e.g. enum x = 3; enum y = 4L; Or will we have to use the {} form? enum {x = 3} enum {y = 4L} -- Derek Parnell Melbourne, Australia skype: derek.j.parnellThe weird thing for me is that this will allow individual enums of any type but grouped enums of only numeric types.The following will work: enum { x = 3, // x is int y = 4L, // y is long } The idea is that for anonymous enums, there is no type for the enumeration as a whole. Therefore, each member of the enumeration can have a different type.enum x = 3; enum y = 4L;It's here somewhere in this thread already.
Dec 28 2007
Okay, just let's reintroduce #define! [duck=] regards, frank
Dec 29 2007
On Sat, 29 Dec 2007 08:45:09 -0000, 0ffh = <frank youknow.what.todo.interNETz> wrote:Okay, just let's reintroduce #define! [duck=3D] regards, frankThe way mixin's can be abused 'we' kind of have already [crawls into hid= ey = hole]
Dec 29 2007
0ffh wrote:Okay, just let's reintroduce #define! [duck=] regards, frankHeh, it seems that might be the only way to avoid addition of a new keyword AND overload of an old keyword. Maybe once D is cleaned up, we'll end up with C again.... -JJR
Dec 29 2007
On Sat, 29 Dec 2007 20:58:43 -0000, John Reimer <terminal.node gmail.com==wrote:0ffh wrote:Okay, just let's reintroduce #define! [duck=3D] regards, frankHeh, it seems that might be the only way to avoid addition of a new =keyword AND overload of an old keyword. Maybe once D is cleaned up, we'll end up with C again.... -JJRNever a grassy knoll around when you need one.
Dec 29 2007