digitalmars.D - Extended Type Design.
- Bruno Medeiros (11/11) Mar 14 2007 What is the status of the experimental designs for the "storage classes"...
- Andrei Alexandrescu (See Website For Email) (21/29) Mar 15 2007 We have talked about a design. In short, the intent is to define three
- Daniel Keep (15/55) Mar 15 2007 This is fantastic news. I'm really happy to know you guys are making
- Andrei Alexandrescu (See Website For Email) (31/39) Mar 15 2007 Thank you! In fact, it did take an embarrassingly long time to implement...
- kris (5/68) Mar 15 2007 ... and return values: "const char[] immutableTextProp()" ?
- Derek Parnell (22/82) Mar 16 2007 I'm not sure about that last one. Does this mean that p2 points to an in...
- Andrei Alexandrescu (See Website For Email) (8/11) Mar 16 2007 You can use "super const". We should be really really careful about
- mike (16/23) Mar 16 2007 =
- torhu (9/17) Mar 16 2007 Wouldn't a "final const" or "const final" pointer be like using const
- Andrei Alexandrescu (See Website For Email) (7/27) Mar 16 2007 From your email I see you are Austrian, so I'm surprised. :o) German is...
- mike (32/37) Mar 16 2007 *scratches head*
- Bruno Medeiros (13/29) Mar 16 2007 So instead of making D like Cobol we make it like APL ? :/
- Andrei Alexandrescu (See Website For Email) (5/32) Mar 16 2007 No. Ada is like Pascal, but worse :oO.
- Andrei Alexandrescu (See Website For Email) (28/50) Mar 16 2007 Good point. There is a little exception here. People expect that when
-
Derek Parnell
(41/93)
Mar 16 2007
But you didn't answer my question? What is the value of the int to - Andrei Alexandrescu (See Website For Email) (30/126) Mar 16 2007 I would love to. It is only for the sake of compatibility with existing
- Dan (14/14) Mar 16 2007 Wow...
- Andrei Alexandrescu (See Website For Email) (6/32) Mar 16 2007 I'm not sure what this is meant to convey.
- Derek Parnell (15/44) Mar 16 2007 It is trying to convey the difficultly in determining which
- Andrei Alexandrescu (See Website For Email) (3/46) Mar 16 2007 final int[int**][]*[const char[]][3][17][3,17]* x;
- Walter Bright (2/9) Mar 16 2007 final int[int**][]*[ const(char[]) ][3][17][3,17]* x;
- Daniel Keep (12/23) Mar 16 2007 Hmm... I think either one of you (Walter and Andrei) got bitten by the
- Andrei Alexandrescu (See Website For Email) (4/21) Mar 16 2007 No, in this context the parens would be simply optional. Only when const...
- Derek Parnell (12/22) Mar 17 2007 Are you serious????
- Deewiant (17/36) Mar 17 2007 Or you want it to be static:
- Andrei Alexandrescu (See Website For Email) (3/24) Mar 17 2007 Because you didn't suggest a better design. :o)
- Bill Baxter (7/27) Mar 16 2007 This:
- Frits van Bommel (26/31) Mar 16 2007 ---
- Daniel Keep (24/46) Mar 16 2007 $ dmd -v1
- Bill Baxter (8/30) Mar 16 2007 The python Numpy project has that too. There have been a lot of changes...
-
Dave
(9/33)
Mar 23 2007
- Andrei Alexandrescu (See Website For Email) (3/8) Mar 23 2007 I think this is a valid point.
- Dave (8/18) Mar 24 2007 Maybe a few more justifications for getting rid of the exceptions:
- Don Clugston (16/39) Mar 16 2007 Does this last category include some of the current use of D const -- a
- Frits van Bommel (6/40) Mar 16 2007 [snip]
- sclytrack (18/19) Mar 16 2007 [snip]
- Andrei Alexandrescu (See Website For Email) (10/24) Mar 16 2007 Yet you write static const not staticconst; public static not
- Bill Baxter (5/32) Mar 16 2007 So you mean foreach(reverse) then? I do like that! You're right that
- Sean Kelly (6/10) Mar 16 2007 This actually came up in more general terms:
- Bill Baxter (11/24) Mar 16 2007 You have it using foreach!(arg) syntax there. But it's not really a
- Sean Kelly (4/23) Mar 16 2007 The syntax isn't really important. I was mostly looking for a way to
- Andrei Alexandrescu (See Website For Email) (6/39) Mar 16 2007 Possibly even without the parens:
- Bill Baxter (12/57) Mar 16 2007 Except then 'reverse' would have to be a keyword too, no?
- Kevin Bealer (12/62) Mar 21 2007 I think the theory is that, like scope(exit), where the 'exit' is not
- Kevin Bealer (29/59) Mar 21 2007 How about the '1984' syntax?
- Andrei Alexandrescu (See Website For Email) (3/14) Mar 21 2007 Swap these two names.
- Chris Nicholson-Sauls (22/97) Mar 22 2007 Disclaimer: My current best understanding.
- Andrei Alexandrescu (See Website For Email) (8/51) Mar 16 2007 Yes, super const is trivially convertible to const. Const alone really
- Walter Bright (3/6) Mar 16 2007 True. If we have readonly and const, I expect endless confusion about
- Benji Smith (4/11) Mar 16 2007 Not to mention if you also have 'readsometimes'. Nobody'll EVER figure
- Andrei Alexandrescu (See Website For Email) (9/52) Mar 16 2007 If we get rid of lazy, I'll sacrifice a lamb :o).
- Don Clugston (14/71) Mar 16 2007 My problem is, I don't see any connection between "don't touch" and
- Andrei Alexandrescu (See Website For Email) (12/27) Mar 16 2007 The difference between math and computer memory is that all too often in...
- Frits van Bommel (14/54) Mar 16 2007 I don't think he's arguing against immutable views, just against calling...
- Don Clugston (2/34) Mar 16 2007 Exactly. Thank you. I'm purely concerned about the name.
- Benji Smith (23/30) Mar 16 2007 Really? I'd think super const would be used all the time. Anywhere a
- Deewiant (24/26) Mar 16 2007 Which isn't that rare, see the following link:
- Andrei Alexandrescu (See Website For Email) (17/47) Mar 16 2007 Working in NLP myself, I totally disagree. Natural language is rife with...
- Deewiant (22/51) Mar 16 2007 Oh, I didn't say I was of that opinion myself. In fact, I have a tendenc...
- Andrei Alexandrescu (See Website For Email) (8/12) Mar 16 2007 Well how about "real const" then :oD.
- Bill Baxter (10/29) Mar 16 2007 Doh! 'real const' of course... how could I leave that one out.
- Sean Kelly (2/33) Mar 16 2007 'const is back and now its really mad' ?
- Benji Smith (31/40) Mar 16 2007 I've also worked in NLP quite a bit, but I don't think the constructs of...
- Andrei Alexandrescu (See Website For Email) (15/38) Mar 16 2007 [snip]
- Benji Smith (9/21) Mar 16 2007 Good point. I like kris's suggestion to get rid of the "const" keyword
- Andrei Alexandrescu (See Website For Email) (3/29) Mar 16 2007 Believe me, I pored over thesauri for a long, long time.
- Walter Bright (3/5) Mar 16 2007 There's some experience with that: the alias and typedef declarations.
- Bill Baxter (4/11) Mar 16 2007 What about 'immutable' for 'really can't change'/'superconst', and const...
- Andrei Alexandrescu (See Website For Email) (4/16) Mar 16 2007 I like it, and suggested it at a point. Walter said that it's bad
- kris (10/33) Mar 16 2007 So, "invariant" is already a keyword ... what about that?
- Andrei Alexandrescu (See Website For Email) (4/42) Mar 16 2007 I completely missed that one. I think it's a good idea to look into it
- kris (6/24) Mar 16 2007 yw
- Bill Baxter (9/32) Mar 16 2007 Typically with invariants in CS the meaning is that "you can change all
- Walter Bright (6/10) Mar 17 2007 I agree. I think:
- Derek Parnell (19/22) Mar 17 2007 On Sat, 17 Mar 2007 19:09:16 -0700, Walter Bright wrote:
- Walter Bright (19/33) Mar 17 2007 No. This applies to rebinding of a name:
- Andrei Alexandrescu (See Website For Email) (11/19) Mar 17 2007 By the way, "invariant" is a lifesaver. Everybody and their sister in
- Alex Burton (6/32) Mar 18 2007 Another option I'd like to have at least considered is the finding of a ...
- Andrei Alexandrescu (See Website For Email) (7/40) Mar 18 2007 Type inference will reduce the need for littering code with "const" a
- Bill Baxter (13/60) Mar 18 2007 What about the ability to deduce only parts of a type?
- Andrei Alexandrescu (See Website For Email) (6/69) Mar 18 2007 assert(is(const typeof(var) == typeof(var)));
- Bruno Medeiros (7/81) Mar 19 2007 Why not just
- Derek Parnell (87/144) Mar 18 2007 I'm sure its just a terminology problem I'm having, but I still can't
- James Dennett (25/72) Mar 18 2007 It's just saying that "T" and "const T" are different types
- Derek Parnell (31/56) Mar 18 2007 Oh?! Is that all. That is easy to understand, but it does not help me
- jovo (12/26) Mar 19 2007 But I think it is'nt key point here. As I understand, const
- Andrei Alexandrescu (See Website For Email) (3/30) Mar 19 2007 Yes. D's const is transitive.
- jovo (8/11) Mar 19 2007 So:
- Andrei Alexandrescu (See Website For Email) (5/16) Mar 19 2007 So rarely that we decided they can be ruled out. They'd complicate the
- Bruno Medeiros (35/162) Mar 19 2007 It's likely the following:
- Chris Nicholson-Sauls (9/15) Mar 19 2007 Its my understanding that 'invariant' becomes part of the type, like 'co...
- Walter Bright (25/25) Mar 20 2007 Bruno has answered your specific questions, so I'll take a more general
- Derek Parnell (45/65) Mar 20 2007 I used to use the verb 'to assign' for this concept. I guess that's stil...
- Andrei Alexandrescu (See Website For Email) (13/60) Mar 20 2007 You may want to modernize. "Assign" doesn't quite catch the notion of
- Derek Parnell (24/86) Mar 20 2007 Okay, if you say so, but I'm not having an issue with the concept of
- Andrei Alexandrescu (See Website For Email) (6/43) Mar 20 2007 No. The difference is major. The binding to Platonic values clarifies
- jovo (14/23) Mar 20 2007 Actually, when I use this term:
- Bruno Medeiros (12/34) Mar 23 2007 Huh, " "Assign" doesn't quite catch the notion of indirect reference",
- Andrei Alexandrescu (See Website For Email) (4/41) Mar 23 2007 That is what really happens, but won't help understanding references. So...
- Bruno Medeiros (6/49) Mar 23 2007 Yes, that you've said already, what I would like to know is why. :P
- Bruno Medeiros (9/16) Mar 23 2007 Since the above case wasn't answered, I will. The "Foo g = f;" statement...
- Bruno Medeiros (12/44) Mar 23 2007 So 'final' will be a storage class and not a type modifier? That's one
- Daniel Keep (14/56) Mar 23 2007 I imagine it would be (invariant Foo*): an invariant pointer to a
- Bruno Medeiros (9/59) Mar 24 2007 No, that's not possible. It was mentioned before in another post:
- Daniel Keep (13/70) Mar 24 2007 You are, of course, right. Damnit. Just when I thought I understood
- Don Clugston (19/32) Mar 19 2007 Assuming that 'invariant' = really constant, 'const' = C++ pseudo-const....
- Andrei Alexandrescu (See Website For Email) (25/47) Mar 19 2007 Great to hear that!
- Frits van Bommel (8/14) Mar 19 2007 I think one of us misunderstood.
- Andrei Alexandrescu (See Website For Email) (4/19) Mar 19 2007 Well, I looked up "want" in my dictionary and parsed the sentence
- Frits van Bommel (3/22) Mar 19 2007 Did you look up "would" as well? :P
- Sean Kelly (13/74) Mar 19 2007 Great perhaps, but it does suggest that 'const' should perhaps be the
- Andrei Alexandrescu (See Website For Email) (5/38) Mar 19 2007 No. There will be far more uses for const than for invariant. You can
- kris (20/70) Mar 19 2007 How about some further example? Given these sigs:
- Andrei Alexandrescu (See Website For Email) (30/54) Mar 19 2007 void fooish (const ref Foo foo) {}
- Sean Kelly (20/43) Mar 19 2007 I assume this is because a char[] is actually a struct containing a
- Andrei Alexandrescu (See Website For Email) (16/50) Mar 19 2007 That is correct. For an understanding of a ~= b, think of it as a = a ~
- Daniel Keep (16/89) Mar 19 2007 Hang on... wouldn't that need to be the signature of barish in the first
- Andrei Alexandrescu (See Website For Email) (4/40) Mar 19 2007 "Nobody said all examples must compile" -- Andrei
- kris (11/86) Mar 19 2007 Good; thanks. BTW: #1 was a tricky question, as Daniel spotted, since it...
- Andrei Alexandrescu (See Website For Email) (7/97) Mar 19 2007 Nobody said all examples must compile :o). In short, you won't be able
- Derek Parnell (109/125) Mar 19 2007 On Mon, 19 Mar 2007 15:05:29 -0700, Andrei Alexandrescu (See Website For
- Andrei Alexandrescu (See Website For Email) (29/136) Mar 19 2007 Correct.
- Derek Parnell (57/143) Mar 19 2007 LOL ... I realize that. Some people are just naturals at it.
- Andrei Alexandrescu (See Website For Email) (32/35) Mar 19 2007 Nonono. Const means: it might have originated as a variable, and
- Derek Parnell (38/48) Mar 19 2007 Yeah ... but that's not what I was talking about. But be that as it may,...
- Andrei Alexandrescu (See Website For Email) (12/61) Mar 19 2007 Fails. fc would change bits not belonging to itself, and "const" makes
- Bill Baxter (12/17) Mar 19 2007 I think discussion would much improved if big changes like this actually...
- Andrei Alexandrescu (See Website For Email) (5/24) Mar 19 2007 I agree. (How couldn't I? Flattery goes a long way :o).)
- Bill Baxter (17/43) Mar 19 2007 I was thinking more of Python's PEPs, but yeh, same deal. I like PEPs
- Kirk McDonald (14/68) Mar 19 2007 The PEP numbers are also a convenient way to refer to certain issues or
- Andrei Alexandrescu (See Website For Email) (3/70) Mar 19 2007 I, too, think that's a great idea.
- Derek Parnell (11/14) Mar 19 2007 Amen to that.
- Andrei Alexandrescu (See Website For Email) (3/14) Mar 19 2007 I thank you folks. Sharing is great. Studying alone is learning from a f...
- jovo (10/17) Mar 20 2007 No, it can not.
- jovo (7/22) Mar 20 2007 Ooops! :)
- Kirk McDonald (7/13) Mar 19 2007 Now that I like. Reminds me very much of Python.
- jovo (6/32) Mar 20 2007 void fooish(const ref Foo foo) {
- Andrei Alexandrescu (See Website For Email) (16/48) Mar 20 2007 Not allowed. The type of foo is const(ref(Foo)). When you try to assign
- Don Clugston (19/44) Mar 20 2007 Sorry, I didn't explain myself very well. I meant that this proposal
- Frits van Bommel (14/59) Mar 20 2007 I completely agree with *that* :).
- Don Clugston (6/25) Mar 20 2007 Yes. The point is that for some uses of C++ const, you have to use
- Andrei Alexandrescu (See Website For Email) (6/32) Mar 20 2007 I think the shock will be mollified by the explanation that const is for...
- Walter Bright (15/21) Mar 20 2007 I also have to always stop and think about what it means. Const in C++
- Bruno Medeiros (10/47) Mar 20 2007 Huh? Wait a second, but won't D have the same issue, albeit with
- Tyler Knott (4/12) Mar 20 2007 invariant Foo* or const Foo*, depending on whichever is most appropriate...
- Chris Nicholson-Sauls (17/32) Mar 20 2007 As I understand, there will be an implicit cast of mutables to immutable...
- Tyler Knott (7/12) Mar 20 2007 Actually, I take back what I said in my previous post in this thread. T...
- Bruno Medeiros (8/25) Mar 22 2007 Well, yes, but is 'invariant' transitive like const? I think it is (but
- Tyler Knott (3/8) Mar 22 2007 D'oh, of course! It's legal to modify data referenced by foo, which mak...
- Chris Nicholson-Sauls (7/31) Mar 23 2007 Actually, having thought over it a few times, what I would really expect...
- Andrei Alexandrescu (See Website For Email) (5/40) Mar 23 2007 Don't. It's entirely understandable to be confused. Extremely little
- Bruno Medeiros (12/27) Mar 22 2007 Let's suppose it's const Foo* (the less restrictive option). Even so,
- Daniel Keep (13/46) Mar 22 2007 Honestly, I don't think that's going to happen :P
- Bruno Medeiros (8/49) Mar 23 2007 No, another way to solve that is to have 'final' be a type modifier as w...
- Daniel Keep (23/74) Mar 23 2007 I think the problem with that is that
- Lars Ivar Igesund (7/21) Mar 20 2007 I agree with Don here.
- kris (14/34) Mar 20 2007 So do I
- Andrei Alexandrescu (See Website For Email) (8/46) Mar 20 2007 I think the 5 letters to 9 letters a difference, especially when
- kris (15/40) Mar 20 2007 Yeah, I know. Except there's three flies in the ointment:
- Andrei Alexandrescu (See Website For Email) (24/75) Mar 20 2007 I don't think so. Const becomes less precise, but maybe code wasn't
- torhu (17/25) Mar 20 2007 I think someone, sometime mentioned changing the meaning of the 'in'
- Don Clugston (31/67) Mar 21 2007 Actually, I have not tried to come up with a better choice.
- Bill Baxter (26/32) Mar 21 2007 I dunno about that. Yes if you're talking about physical constants or
- Don Clugston (7/31) Mar 22 2007 I discussed that already. The proposed 'const' is variable in the
- James Dennett (21/47) Mar 20 2007 Indeed, and seems to represent a misunderstand of what
- Carlos Santander (16/29) Mar 19 2007 I haven't finished reading everything on this thread yet, so I don't kno...
- Bill Baxter (12/77) Mar 16 2007 If you just want something that sounds like more const than const using
- Frits van Bommel (3/37) Mar 16 2007 I think that sums up my take on this pretty well. Thanks for saving me
- Benji Smith (6/6) Mar 16 2007 I should also add that, in my opinion, any design where "const" means
- Andrei Alexandrescu (See Website For Email) (4/7) Mar 16 2007 Then how would you call "value that's not mutable through this alias" in...
- kris (15/24) Mar 16 2007 there are explicit names for that sort of thing; "immutable", "readonly"...
- Sean Kelly (5/32) Mar 16 2007 ++vote
- Andrei Alexandrescu (See Website For Email) (5/7) Mar 16 2007 The problem with 'view' is that it's a noun, while final and const are
- kris (2/12) Mar 16 2007 yuh, fair point :(
-
Derek Parnell
(14/22)
Mar 16 2007
As in "to view or not to view, that is the question"
- Andrei Alexandrescu (See Website For Email) (5/29) Mar 16 2007 I must not see the connection. "super const int" is a suggestive
- Sean Kelly (3/11) Mar 16 2007 It's probably not terribly helpful, but 'view' is also a verb.
- kris (5/15) Mar 16 2007 How about this? Using existing keywords, with a rename of "const":
- Benji Smith (5/10) Mar 16 2007 Actually, that's pretty good too. Getting rid of the keyword "const"
- Frits van Bommel (9/14) Mar 16 2007 These two are fine by me.
- Andrei Alexandrescu (See Website For Email) (7/24) Mar 16 2007 Much of the terminological problem is that it's hard to express const's
- Bill Baxter (5/15) Mar 16 2007 And 'view' is also probably a very popular name for a variable thanks to...
- Andrei Alexandrescu (See Website For Email) (8/24) Mar 16 2007 However, viewonly is a possibility that's particularly expressive. As
- Walter Bright (10/14) Mar 16 2007 Changing inout to ref would be a very long process in several stages:
- Andrei Alexandrescu (See Website For Email) (5/22) Mar 16 2007 I will notice that that process didn't start for the infamous magic
- Bill Baxter (10/27) Mar 16 2007 Why not just stop at '1'? Inout is very descriptive if what you're
- Andrei Alexandrescu (See Website For Email) (6/31) Mar 16 2007 That's very awkward. Exact synonyms fare real bad in all languages I
- Derek Parnell (8/10) Mar 16 2007 I am more than happy to change my source code if the result is easier to
- Andrei Alexandrescu (See Website For Email) (9/34) Mar 16 2007 No, just no gratuitous incompatibilities and misunderstanding. For
- Benji Smith (7/16) Mar 16 2007 I have no special love (nor contempt, of course) for C++ immigrants and
- Derek Parnell (9/26) Mar 16 2007 Thank you Benji ... I've been trying to write a response to that but
- Andrei Alexandrescu (See Website For Email) (8/24) Mar 16 2007 Well, you see - quot capita, tot sententiae. :o) It's not about
- Bruno Medeiros (5/24) Mar 16 2007 Same opinion here. What makes D good is fixing broken constructs from C+...
- Andrei Alexandrescu (See Website For Email) (3/25) Mar 16 2007 Same opinion here too.
- Walter Bright (28/31) Mar 16 2007 I hear you. I've always disliked C++'s mutable const.
- Benji Smith (15/29) Mar 16 2007 I appreciate the thought you guys have put into it. And the
- Walter Bright (2/4) Mar 16 2007 Not that I can think of.
- kris (8/49) Mar 16 2007 Glad to hear you guys are open to considerations. For purpose of
- Sean Kelly (22/40) Mar 16 2007 I very much agree. But with little information about how these new
- Andrei Alexandrescu (See Website For Email) (17/61) Mar 16 2007 Very important. Often you want to bind a pointer to something and make
- Sean Kelly (30/90) Mar 16 2007 Perhaps this should be rewritten as "often one wants to..." I just said...
- Andrei Alexandrescu (See Website For Email) (9/107) Mar 16 2007 I think "final" is mostly useful in class and struct members.
- Sean Kelly (12/48) Mar 16 2007 I must be missing something here. I expected this to be the point of
- Bill Baxter (9/14) Mar 16 2007 How about taking Andrei's observation about extern(C) and scope(exit)
- Geoff Carlton (33/53) Mar 17 2007 Well, I'm a C++ programmer and I think the last two are much more
- Andrei Alexandrescu (See Website For Email) (16/47) Mar 16 2007 No. super const deals with pointers and transitivity. Final deals with
- Frits van Bommel (29/36) Mar 16 2007 How would you have people distinguish char/wchar/dchar without running
- Walter Bright (6/10) Mar 16 2007 My perception of that is different. I used to do embedded systems, and
- Frits van Bommel (14/25) Mar 16 2007 Perhaps, but my perception of 'const' is different ;). Particularly, it
- Sean Kelly (7/26) Mar 16 2007 So *that's* why Win32 doesn't complain when constant data is modified
- Frits van Bommel (18/30) Mar 16 2007 [snip]
- Don Clugston (9/16) Mar 16 2007 Hospitality to C++ immigrants is definitely important. But since C++
- Andrei Alexandrescu (See Website For Email) (6/22) Mar 16 2007 Let me say it again: we know why it's broken. We will provide a fixed
- Benji Smith (6/15) Mar 16 2007 Aha. In that case, what would you think of the declaration:
- Andrei Alexandrescu (See Website For Email) (3/20) Mar 16 2007 This should be a compiler error.
- Benji Smith (14/26) Mar 16 2007 Cool. That's what I'd expect.
- Sean Kelly (3/20) Mar 16 2007 Well this explains a lot. I'd misunderstood as well.
- Derek Parnell (7/43) Mar 16 2007 Well expressed. My think is almost 100% aligned with these thoughts abov...
- Joel C. Salomon (4/9) Mar 16 2007 How about “const const”? No new keywords, no reuse of keywords in
- Dan (1/5) Mar 16 2007 Noticeable alright! I can't even type those characters. : D
- kris (4/17) Mar 16 2007 The whole things about adding *more* constantness to const screams one
- Benji Smith (5/23) Mar 16 2007 Bingo. It's like trying to describe something as "impossible
- Andrei Alexandrescu (See Website For Email) (3/26) Mar 16 2007 You're "dead dead" right! :o)
- Derek Parnell (11/16) Mar 16 2007 Reminds me a bit of the joke ...
- Walter Bright (7/10) Mar 16 2007 Reminds me of the old assembler program:
- kris (2/16) Mar 16 2007 LOL
- Walter Bright (2/19) Mar 16 2007 You know those teenagers with the overclocked CPUs...
- Sean Kelly (2/14) Mar 16 2007 LOL
- Andrei Alexandrescu (See Website For Email) (4/13) Mar 16 2007 It was on the plate briefly. Probably it would be an uphill battle to
- Joel C. Salomon (16/21) Mar 17 2007 I’m still kinda shaky on the question of why the various extra
- janderson (7/47) Mar 16 2007 Thanks for the update:
- Frits van Bommel (7/13) Mar 16 2007 If you mean parsers, I don't think that'll be much of a problem. 'const'...
- Andrei Alexandrescu (See Website For Email) (5/56) Mar 16 2007 The damndest thing is that const! (as well as const) _is_ a template:
- eao197 (24/31) Mar 16 2007 On Fri, 16 Mar 2007 00:16:48 +0300, Andrei Alexandrescu (See Website For...
- Andrei Alexandrescu (See Website For Email) (6/39) Mar 16 2007 Yes, that's part of the plan. Moreover, you'll likely have the ability
- eao197 (8/12) Mar 16 2007 Thanks, I'm glad to hear that!
- Andrei Alexandrescu (See Website For Email) (3/15) Mar 16 2007 Actually, this is exactly true. D 2.0.
- =?UTF-8?B?QW5kZXJzIEYgQmrDtnJrbHVuZA==?= (3/5) Mar 16 2007 Or perhaps it should be called D++ ?
- eao197 (7/10) Mar 16 2007 No, at first there must be 'D with macros' (like 'C with classes') and
- Dan (7/9) Mar 16 2007 *shudder*
- Andrei Alexandrescu (See Website For Email) (11/16) Mar 16 2007 Simplistic does not mean simpler. Your system would be unable to express...
- Derek Parnell (21/30) Mar 16 2007 Maybe the concepts but I'm not so sure about the usage.
- Andrei Alexandrescu (See Website For Email) (6/41) Mar 16 2007 Exactly. All I'm saying is that if you go through the steps of your
- eao197 (16/27) Mar 16 2007 My expirience in C++ and Ruby says that a language must have no macro
- Walter Bright (6/8) Mar 16 2007 D will get macros - but they won't be text processing macros, they'll be...
- eao197 (8/16) Mar 17 2007 It is very interesting to hear that. Could you say more about the future...
- Walter Bright (15/27) Mar 17 2007 It's pretty simple:
- Daniel Keep (22/49) Mar 17 2007 Bosco: And I might have another item of interest behind the counter...
- Walter Bright (10/16) Mar 17 2007 No. Abner Hale thwacks such things with "abomination!"
- Sean Kelly (13/20) Mar 17 2007 Yup. It sounds like the implementation will really be quite like the
- Marcin Kuszczak (21/39) Mar 17 2007 And what about mixin templates? Couldn't they just be fixed to do this w...
- Walter Bright (1/1) Mar 17 2007 See new thread for reply.
- janderson (41/73) Mar 17 2007 On naming why not use mixin, since they are so similar?
- eao197 (18/32) Mar 17 2007 As I can see the content of macro body will be inserted into AST in the ...
- Reiner Pope (8/47) Mar 16 2007 So, would this allow you to express the associative array requirement, t...
- Andrei Alexandrescu (See Website For Email) (3/55) Mar 16 2007 Yes.
- Dave (4/21) Mar 23 2007 I haven't noticed 'ref' come-up on subsequent posts, but I would strongl...
- Dan (4/6) Mar 16 2007 Actually, Bill, it's part of the language spec.
- Frits van Bommel (8/16) Mar 16 2007 The only thing even close to that is this:
- Bill Baxter (3/11) Mar 16 2007 Read that part of the spec closely, Dan.
- Reiner Pope (19/33) Mar 16 2007 Is there anything in your discussion about compile-time constants (the s...
- Andrei Alexandrescu (See Website For Email) (12/47) Mar 16 2007 I understand this is high on Walter's list. The syntax discussed is:
- Reiner Pope (46/104) Mar 16 2007 Good to hear that.
- Andrei Alexandrescu (See Website For Email) (6/116) Mar 17 2007 Good question. It must be a template by the pigeonhole principle: each
- Reiner Pope (7/50) Mar 17 2007 But how about the runtime implementation of match()? There's no code
- Reiner Pope (12/15) Mar 17 2007 So is there going to be a way to specify at the function (or template)
- Bruno Medeiros (248/249) Mar 17 2007 I asked this because yesterday, out of nowhere, I started thinking about...
- Alex Burton (20/59) Mar 18 2007 I didn't see any discussion of how a member function is to be marked as ...
- Tyler Knott (109/109) Mar 19 2007 I think I've got this. Is the following right?
- Andrei Alexandrescu (See Website For Email) (37/71) Mar 19 2007 Correct.
- Derek Parnell (27/32) Mar 19 2007 Can 'const' and 'invariant' apply to structs, especially ones that conta...
- Andrei Alexandrescu (See Website For Email) (12/40) Mar 19 2007 That code is fine. I should have said "const and invariant make sense
- Bruno Medeiros (5/65) Mar 20 2007 What?? If f is 'const', how are any of those "f.s =" assignments allowed...
- Tyler Knott (23/26) Mar 20 2007 Because f is a POD (Plain Old Data) structure and not a reference you ca...
- Bruno Medeiros (5/24) Mar 21 2007 Duh, of course. I misread and was thinking Foo was a class and not a str...
What is the status of the experimental designs for the "storage classes" manipulation that Andrei and others where thinking of for D. The last I heard from it was Andrei's max suggestion from his max design challenge, however, I think that suggestion may suffer from some problems in regards to the "maxtype" requirement, plus it is wholly incomplete in regards to how storage classes interact between each other. Like Andrei said, what is a "const inout lazy const char[]", if valid at all? Is there any news here? Is there a working(aka complete) design? -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Mar 14 2007
Bruno Medeiros wrote:What is the status of the experimental designs for the "storage classes" manipulation that Andrei and others where thinking of for D. The last I heard from it was Andrei's max suggestion from his max design challenge, however, I think that suggestion may suffer from some problems in regards to the "maxtype" requirement, plus it is wholly incomplete in regards to how storage classes interact between each other. Like Andrei said, what is a "const inout lazy const char[]", if valid at all? Is there any news here? Is there a working(aka complete) design?We have talked about a design. In short, the intent is to define three flavors of immutability: a) final - a simple storage class controlling the immutability of the bits allocated for the symbol per se; b) const - type qualifier meaning an immutable view of an otherwise modifiable data. const does not control the bits of the object, only the storage addressed indirectly by it (transitively); c) "superconst" - denoted as "const!" or "super const": type qualifier meaning that the data is genuinely unmodifiable. There is talk about deprecating lazy if it's best implemented via other mechanisms. There is also talk about deprecating "inout" in favor of "ref" on grounds that the often-useful "inout const" is likely to become To read a declaration like "const inout lazy const char[]", you can first parenthesize it appropriately: const(inout(lazy(const(char[])))) The lazy thing is really a delegate that returns a const char[]. The inout around it passes that delegate by reference, and the const at the top makes the delegate immutable. Andrei
Mar 15 2007
Andrei Alexandrescu (See Website For Email) wrote:Bruno Medeiros wrote:This is fantastic news. I'm really happy to know you guys are making progress on this. So if I understand this right: * "final int*" is an immutable pointer that points to mutable data, * "const int*" is a mutable pointer to immutable data, but that data *may* be mutable in another context (ie: const((new int[10]).ptr)) and * "const! int*" means "seriously, this *will not* change". In any case, great to know things are moving along :) -- Daniel -- Unlike Knuth, I have neither proven or tried the above; it may not even make sense. v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/What is the status of the experimental designs for the "storage classes" manipulation that Andrei and others where thinking of for D. The last I heard from it was Andrei's max suggestion from his max design challenge, however, I think that suggestion may suffer from some problems in regards to the "maxtype" requirement, plus it is wholly incomplete in regards to how storage classes interact between each other. Like Andrei said, what is a "const inout lazy const char[]", if valid at all? Is there any news here? Is there a working(aka complete) design?We have talked about a design. In short, the intent is to define three flavors of immutability: a) final - a simple storage class controlling the immutability of the bits allocated for the symbol per se; b) const - type qualifier meaning an immutable view of an otherwise modifiable data. const does not control the bits of the object, only the storage addressed indirectly by it (transitively); c) "superconst" - denoted as "const!" or "super const": type qualifier meaning that the data is genuinely unmodifiable. There is talk about deprecating lazy if it's best implemented via other mechanisms. There is also talk about deprecating "inout" in favor of "ref" on grounds that the often-useful "inout const" is likely to become To read a declaration like "const inout lazy const char[]", you can first parenthesize it appropriately: const(inout(lazy(const(char[])))) The lazy thing is really a delegate that returns a const char[]. The inout around it passes that delegate by reference, and the const at the top makes the delegate immutable. Andrei
Mar 15 2007
Daniel Keep wrote:This is fantastic news. I'm really happy to know you guys are making progress on this.Thank you! In fact, it did take an embarrassingly long time to implement something within all of the self-imposed constraints, but now we're really happy with the result.So if I understand this right: * "final int*" is an immutable pointer that points to mutable data,Yes. For example: int a, b; final int * p = &a; *p = 5; // fine p = &b; // error! Cannot rebind final symbol!* "const int*" is a mutable pointer to immutable data, but that data *may* be mutable in another context (ie: const((new int[10]).ptr)) andExactly. For example: int a; const int * p = &a; *p = 5; // error! Cannot modify const data! a = 5; // yah, modify data under the feet of p This is a great feature for calling functions and providing "isolated" interfaces. For example, say you write a function void print(char[]); You want to clarify to the caller that you NEVER modify their data. So you define the function as: void print(const char[]); Then callers can call print with mutable or immutable data; it makes no difference to print. Unlike in C++, it takes much more effort to cast away constness, and the results are never well-defined.* "const! int*" means "seriously, this *will not* change".Right. For example: int a; const! int* p = &a; // error! cannot convert int* to const! int* final int b = 42; const! int* p1 = &b; // yah, b is truly immutable const! int* p2 = new const! int; // yah Andrei
Mar 15 2007
Andrei Alexandrescu (See Website For Email) wrote:Daniel Keep wrote:... and return values: "const char[] immutableTextProp()" ? Just a thought on the const! syntax; it looks somewhat odd, and perhaps too much like template syntax? How about calling one of the "const" types "readonly" or "view" instead?This is fantastic news. I'm really happy to know you guys are making progress on this.Thank you! In fact, it did take an embarrassingly long time to implement something within all of the self-imposed constraints, but now we're really happy with the result.So if I understand this right: * "final int*" is an immutable pointer that points to mutable data,Yes. For example: int a, b; final int * p = &a; *p = 5; // fine p = &b; // error! Cannot rebind final symbol!* "const int*" is a mutable pointer to immutable data, but that data *may* be mutable in another context (ie: const((new int[10]).ptr)) andExactly. For example: int a; const int * p = &a; *p = 5; // error! Cannot modify const data! a = 5; // yah, modify data under the feet of p This is a great feature for calling functions and providing "isolated" interfaces. For example, say you write a function void print(char[]); You want to clarify to the caller that you NEVER modify their data. So you define the function as: void print(const char[]); Then callers can call print with mutable or immutable data; it makes no difference to print. Unlike in C++, it takes much more effort to cast away constness, and the results are never well-defined.* "const! int*" means "seriously, this *will not* change".Right. For example: int a; const! int* p = &a; // error! cannot convert int* to const! int* final int b = 42; const! int* p1 = &b; // yah, b is truly immutable const! int* p2 = new const! int; // yah Andrei
Mar 15 2007
On Thu, 15 Mar 2007 23:45:05 -0700, kris wrote:Andrei Alexandrescu (See Website For Email) wrote:I'm not sure about that last one. Does this mean that p2 points to an int that cannot change and p2 itself can no longer be changed? And what is the value in the int that p2 points to? Can you do this sort of thing ... int x = 5; const! int* p2 = new const! int(x); meaning that p2 now points to a 'final' int whose value is 5, plus p2 can never be changed now either.Daniel Keep wrote:This is fantastic news. I'm really happy to know you guys are making progress on this.Thank you! In fact, it did take an embarrassingly long time to implement something within all of the self-imposed constraints, but now we're really happy with the result.So if I understand this right: * "final int*" is an immutable pointer that points to mutable data,Yes. For example: int a, b; final int * p = &a; *p = 5; // fine p = &b; // error! Cannot rebind final symbol!* "const int*" is a mutable pointer to immutable data, but that data *may* be mutable in another context (ie: const((new int[10]).ptr)) andExactly. For example: int a; const int * p = &a; *p = 5; // error! Cannot modify const data! a = 5; // yah, modify data under the feet of p This is a great feature for calling functions and providing "isolated" interfaces. For example, say you write a function void print(char[]); You want to clarify to the caller that you NEVER modify their data. So you define the function as: void print(const char[]); Then callers can call print with mutable or immutable data; it makes no difference to print. Unlike in C++, it takes much more effort to cast away constness, and the results are never well-defined.* "const! int*" means "seriously, this *will not* change".Right. For example: int a; const! int* p = &a; // error! cannot convert int* to const! int* final int b = 42; const! int* p1 = &b; // yah, b is truly immutable const! int* p2 = new const! int; // yah... and return values: "const char[] immutableTextProp()" ?Hmmmm... does "const char[] X" mean that X.ptr can change, X.length can never change and the data pointed to by X.ptr can never change? Or is "can never" too strong? Is it more that code within the scope of the declaration is not allowed to change those things?Just a thought on the const! syntax; it looks somewhat odd, and perhaps too much like template syntax? How about calling one of the "const" types "readonly" or "view" instead?Yes! "const!" is bad form. Really bad. Horrible in fact. Just make it a new keyword please, without using non-alpha characters. Such as "readonly", "immutable", "keepyourgrubbyhandsoff", ... anything but using "!". -- Derek (skype: derek.j.parnell) Melbourne, Australia "Justice for David Hicks!" 16/03/2007 6:01:40 PM
Mar 16 2007
Derek Parnell wrote:Yes! "const!" is bad form. Really bad. Horrible in fact. Just make it a new keyword please, without using non-alpha characters. Such as "readonly", "immutable", "keepyourgrubbyhandsoff", ... anything but using "!".You can use "super const". We should be really really careful about adding new keywords; D already has tons, and I have a feeling we don't want it to become Cobol or dBase. If there are ways to stay away from new keywords, we'll do so. I do realize that no matter the syntax, there will be people who won't like it. But avoiding adding keywords liberally is an overriding desideratum. Andrei
Mar 16 2007
Am 16.03.2007, 10:19 Uhr, schrieb Andrei Alexandrescu (See Website For = Email) <SeeWebsiteForEmail erdani.org>:You can use "super const". We should be really really careful about =adding new keywords; D already has tons, and I have a feeling we don't==want it to become Cobol or dBase. If there are ways to stay away from new keywords, we'll do so. I do =realize that no matter the syntax, there will be people who won't like==it. But avoiding adding keywords liberally is an overriding desideratu=m.AndreiWhy not "const final" or "final const"? (a) .. final (b) .. const (c) .. const final / final const "super" is for calling constructors and that should be the only use for = = this keyword. -mike -- = Erstellt mit Operas revolution=E4rem E-Mail-Modul: http://www.opera.com/= mail/
Mar 16 2007
mike wrote:Why not "const final" or "final const"? (a) .. final (b) .. const (c) .. const final / final const "super" is for calling constructors and that should be the only use for this keyword.Wouldn't a "final const" or "const final" pointer be like using const for both the pointer and the value in C? // D int x = 5; const final int* p = &x; // C int x = 5; const int * const p = &x;
Mar 16 2007
mike wrote:Am 16.03.2007, 10:19 Uhr, schrieb Andrei Alexandrescu (See Website For Email) <SeeWebsiteForEmail erdani.org>:Because final const and super const express very different realities.You can use "super const". We should be really really careful about adding new keywords; D already has tons, and I have a feeling we don't want it to become Cobol or dBase. If there are ways to stay away from new keywords, we'll do so. I do realize that no matter the syntax, there will be people who won't like it. But avoiding adding keywords liberally is an overriding desideratum. AndreiWhy not "const final" or "final const"? (a) .. final (b) .. const (c) .. const final / final const"super" is for calling constructors and that should be the only use for this keyword.From your email I see you are Austrian, so I'm surprised. :o) German is the most synthetic (as opposed to analytical) language in use, and has the admirable property of building precise terms by combining smaller polysemous terms. Andrei
Mar 16 2007
Am 16.03.2007, 18:59 Uhr, schrieb Andrei Alexandrescu (See Website For = Email) <SeeWebsiteForEmail erdani.org>:Because final const and super const express very different realities.*scratches head* Oh ... I didn't know that final const already HAD a meaning.From your email I see you are Austrian, so I'm surprised. :o) German =is =the most synthetic (as opposed to analytical) language in use, and has==the admirable property of building precise terms by combining smaller ==polysemous terms.Yeah, I'm Austrian, living in the land that has been named after the chi= ef = from battlestar galactica, so I don't really speak german :) We have ou= r = own language, basically, that's why the rest of the german-speaking worl= d = can't understand us. Like the people from Switzerland can't be understoo= d = by anyone but themselves. I like the idea of combining keywords to give them a new meaning, just = using "super" for two totally unrelated concepts worries me a bit. "scop= e" = for instance is great: It has two meanings, but they're completely = related. But using super once as a call and once as a sort of amplifier = = for const seems kind of random. Also I can't help myself but "super cons= t" = just sounds a bit ridiculous to me: ' super duper =FCber const int i =3D 3; // Holy constant, batman! Sorry :) Anyway, I have no better idea, so go for it! -mike -- = Erstellt mit Operas revolution=E4rem E-Mail-Modul: http://www.opera.com/= mail/
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Derek Parnell wrote:So instead of making D like Cobol we make it like APL ? :/ I don't think the problem of Cobol was *having* too many keywords, but rather forcing you to *use* lots of keywords for the simplest things. (Disclaimer: I don't actually know Cobol, I'm imagining it to be like Pascal, but worse) So we should have that in consideration when talking about D. In fact, I think that any general idea of "adding more keywords is bad" is somewhat pernicious: every case should be examined in itself. In some cases it could be worth it, in others not. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DYes! "const!" is bad form. Really bad. Horrible in fact. Just make it a new keyword please, without using non-alpha characters. Such as "readonly", "immutable", "keepyourgrubbyhandsoff", ... anything but using "!".You can use "super const". We should be really really careful about adding new keywords; D already has tons, and I have a feeling we don't want it to become Cobol or dBase. If there are ways to stay away from new keywords, we'll do so. I do realize that no matter the syntax, there will be people who won't like it. But avoiding adding keywords liberally is an overriding desideratum. Andrei
Mar 16 2007
Bruno Medeiros wrote:Andrei Alexandrescu (See Website For Email) wrote:No. Ada is like Pascal, but worse :oO. Cobol has 420 keywords.Derek Parnell wrote:So instead of making D like Cobol we make it like APL ? :/ I don't think the problem of Cobol was *having* too many keywords, but rather forcing you to *use* lots of keywords for the simplest things. (Disclaimer: I don't actually know Cobol, I'm imagining it to be like Pascal, but worse)Yes! "const!" is bad form. Really bad. Horrible in fact. Just make it a new keyword please, without using non-alpha characters. Such as "readonly", "immutable", "keepyourgrubbyhandsoff", ... anything but using "!".You can use "super const". We should be really really careful about adding new keywords; D already has tons, and I have a feeling we don't want it to become Cobol or dBase. If there are ways to stay away from new keywords, we'll do so. I do realize that no matter the syntax, there will be people who won't like it. But avoiding adding keywords liberally is an overriding desideratum. AndreiSo we should have that in consideration when talking about D. In fact, I think that any general idea of "adding more keywords is bad" is somewhat pernicious: every case should be examined in itself. In some cases it could be worth it, in others not.I agree. Andrei
Mar 16 2007
Derek Parnell wrote:Good point. There is a little exception here. People expect that when they write: const char[] str = "Hi!"; they can't modify str nor its characters. So they expect str to be final as well. We then arrange that if const appears in a data definition, that data is automatically made final as well. So the above is equivalent to: final const char[] str = "Hi!"; If you don't want str to be final, do this: const(char[]) str = "Hi!";I'm not sure about that last one. Does this mean that p2 points to an int that cannot change and p2 itself can no longer be changed? And what is the value in the int that p2 points to?int a; const! int* p = &a; // error! cannot convert int* to const! int* final int b = 42; const! int* p1 = &b; // yah, b is truly immutable const! int* p2 = new const! int; // yahCan you do this sort of thing ... int x = 5; const! int* p2 = new const! int(x); meaning that p2 now points to a 'final' int whose value is 5, plus p2 can never be changed now either.Yes, you can.See the exception above. But now consider a function: void say(const char[] data) { ... } The bits of data are a private copy of say, so they can be changed discretionarily (if that's a word). But the bits pointed to by data do not belong to say, so they can't be written. If say wants to be fancy, it can look like this: void say(final const char[] data) { ... } Then data can't be even rebound. The "final" being a storage class, it doesn't appear in the function signature (e.g., in the interface file). Andrei... and return values: "const char[] immutableTextProp()" ?Hmmmm... does "const char[] X" mean that X.ptr can change, X.length can never change and the data pointed to by X.ptr can never change? Or is "can never" too strong? Is it more that code within the scope of the declaration is not allowed to change those things?
Mar 16 2007
On Fri, 16 Mar 2007 02:25:24 -0700, Andrei Alexandrescu (See Website For Email) wrote:Derek Parnell wrote:<G> But you didn't answer my question? What is the value of the int to which p2 is pointing?Good point.I'm not sure about that last one. Does this mean that p2 points to an int that cannot change and p2 itself can no longer be changed? And what is the value in the int that p2 points to?int a; const! int* p = &a; // error! cannot convert int* to const! int* final int b = 42; const! int* p1 = &b; // yah, b is truly immutable const! int* p2 = new const! int; // yahThere is a little exception here.Oh no ... alarms start to sound when I see 'exceptions'. Is it not possible to eliminate this exception?People expect that when they write: const char[] str = "Hi!"; they can't modify str nor its characters. So they expect str to be final as well. We then arrange that if const appears in a data definition, that data is automatically made final as well. So the above is equivalent to: final const char[] str = "Hi!";Are you saying "People expect that when they write ... and so that's what we are going to have D do for them."? Let's see if I got this ... const char[] str = "Hi!"; // Neither 'str' nor it contents can // be changed. final const char[] str2 = "Hi again"; // Means the same as above syntax. const char* chr = "Hi!"; // 'chr' can be changed but the chars // it points to cannot be changed. final const char* chr2 = "Hi!"; // 'chr2' can be not be changed // and neither can its chars. I hope I got this wrong because that is a easy bug maker.If you don't want str to be final, do this: const(char[]) str = "Hi!";You have got to be kidding! This is starting to get unreadable again. As a simple person, if I didn't want something to be 'final', I wouldn't use the 'final' keyword. But you are saying that if I don't want 'final', I not only have to avoid using 'final', I also have to put some of the phrase (and I know I'll never remember which parts) in parenthesis. But wait ... there's more. If I do want it to be 'final' all I have to do is not use the 'final' keyword. Am I getting this right? Is it not possible to make reading code simple?The EXCEPTION (alarms still ringing) seems to be saying that 'const char[] X' means that X.ptr, X.length and the data in X's RAM cannot be changed.Hmmmm... does "const char[] X" mean that X.ptr can change, X.length can never change and the data pointed to by X.ptr can never change? Or is "can never" too strong? Is it more that code within the scope of the declaration is not allowed to change those things?See the exception above.But now consider a function: void say(const char[] data) { ... } The bits of data are a private copy of say, so they can be changed discretionarily (if that's a word). But the bits pointed to by data do not belong to say, so they can't be written. If say wants to be fancy, it can look like this: void say(final const char[] data) { ... }That didn't help. I'm even more confused now. Can I try? ... void say (const char[] data) { data[0] = 'a'; // Allowed but not passed back to caller. data = "ABC"; // Not allowed. }Then data can't be even rebound. The "final" being a storage class, it doesn't appear in the function signature (e.g., in the interface file).Hmmmm ... won't that cause problems for library writers who provide a library and ".di" files? -- Derek Parnell Melbourne, Australia "Justice for David Hicks!" skype: derek.j.parnell
Mar 16 2007
Derek Parnell wrote:On Fri, 16 Mar 2007 02:25:24 -0700, Andrei Alexandrescu (See Website For Email) wrote:The default value of int, which is zero.Derek Parnell wrote:<G> But you didn't answer my question? What is the value of the int to which p2 is pointing?Good point.I'm not sure about that last one. Does this mean that p2 points to an int that cannot change and p2 itself can no longer be changed? And what is the value in the int that p2 points to?int a; const! int* p = &a; // error! cannot convert int* to const! int* final int b = 42; const! int* p1 = &b; // yah, b is truly immutable const! int* p2 = new const! int; // yahI would love to. It is only for the sake of compatibility with existing code.There is a little exception here.Oh no ... alarms start to sound when I see 'exceptions'. Is it not possible to eliminate this exception?I was just trying to minimize the amount of broken code. Also, we need to figure what to do about this: const int capacity = 80; In this context const makes no sense because int does not contain pointers. The above should be: final int capacity = 80;People expect that when they write: const char[] str = "Hi!"; they can't modify str nor its characters. So they expect str to be final as well. We then arrange that if const appears in a data definition, that data is automatically made final as well. So the above is equivalent to: final const char[] str = "Hi!";Are you saying "People expect that when they write ... and so that's what we are going to have D do for them."?Let's see if I got this ... const char[] str = "Hi!"; // Neither 'str' nor it contents can // be changed. final const char[] str2 = "Hi again"; // Means the same as above syntax.Correct.const char* chr = "Hi!"; // 'chr' can be changed but the chars // it points to cannot be changed.Correct. The pointer can be made to point anywhere, but it's looking, no touching.final const char* chr2 = "Hi!"; // 'chr2' can be not be changed // and neither can its chars.Yes.I hope I got this wrong because that is a easy bug maker.How would the bugs be introduced?The problem is that many simple persons have different simple needs. The parens actually help readability a lot when compared to C++ because you don't need to put several const's for complex types.If you don't want str to be final, do this: const(char[]) str = "Hi!";You have got to be kidding! This is starting to get unreadable again. As a simple person, if I didn't want something to be 'final', I wouldn't use the 'final' keyword.But you are saying that if I don't want 'final', I not only have to avoid using 'final', I also have to put some of the phrase (and I know I'll never remember which parts) in parenthesis. But wait ... there's more. If I do want it to be 'final' all I have to do is not use the 'final' keyword. Am I getting this right? Is it not possible to make reading code simple?An intuition that I see reasonable is that const by default engulfs everything to its right: const char[] str = "Hi!"; // same as const(char[] str) = "Hi!"; When it engulfs the symbol, it makes it immutable, hence final. So by putting the parens you limit const's power. But I'd be glad to drop this exception. I'm not sure what Walter and people who'll have to modify their code would say though.I am hearing it. :o)The EXCEPTION (alarms still ringing) seems to be saying that 'const char[] X' means that X.ptr, X.length and the data in X's RAM cannot be changed.Hmmmm... does "const char[] X" mean that X.ptr can change, X.length can never change and the data pointed to by X.ptr can never change? Or is "can never" too strong? Is it more that code within the scope of the declaration is not allowed to change those things?See the exception above.Now, you got it backwards: data's contents belong to the caller, and data's pointer belongs to the callee.But now consider a function: void say(const char[] data) { ... } The bits of data are a private copy of say, so they can be changed discretionarily (if that's a word). But the bits pointed to by data do not belong to say, so they can't be written. If say wants to be fancy, it can look like this: void say(final const char[] data) { ... }That didn't help. I'm even more confused now. Can I try? ... void say (const char[] data) { data[0] = 'a'; // Allowed but not passed back to caller. data = "ABC"; // Not allowed. }No. AndreiThen data can't be even rebound. The "final" being a storage class, it doesn't appear in the function signature (e.g., in the interface file).Hmmmm ... won't that cause problems for library writers who provide a library and ".di" files?
Mar 16 2007
Wow... I've never put this much thought into const/final stuff. Ultimately, the program *cannot* prevent data in memory from being changed. It can at best prevent you from accidentally changing it; hence final and const declarations mean "I don't want anyone to change these, can you raise an error if someone tries to within D?" Also, the problem breaks down to 'what am I declaring const?'. If I declare: const int* x; // is it the pointer, or the int? This doesn't seem important until you get to: const int[int**][]* x; // now what is it? Ultimately, you have this problem going through each and every pointer, array and value. You could theoretically write this: const int[int**][]*[char[]][3][17][3,17]* x; and now what are you going to do? declare it: final const final final const const final final final final final const? Even final const! super const! final! const! doesn't work, in fact I agree it makes it worse. Good luck getting readability with that. Ultimately, something else needs to be developed. Perhaps a character we can use in alongside each item on the type declaration, or we need to be able to hit the whole line in one blow. Just my penny.
Mar 16 2007
Dan wrote:Wow... I've never put this much thought into const/final stuff. Ultimately, the program *cannot* prevent data in memory from being changed. It can at best prevent you from accidentally changing it; hence final and const declarations mean "I don't want anyone to change these, can you raise an error if someone tries to within D?" Also, the problem breaks down to 'what am I declaring const?'. If I declare: const int* x; // is it the pointer, or the int? This doesn't seem important until you get to: const int[int**][]* x; // now what is it? Ultimately, you have this problem going through each and every pointer, array and value. You could theoretically write this: const int[int**][]*[char[]][3][17][3,17]* x; and now what are you going to do? declare it: final const final final const const final final final final final const? Even final const! super const! final! const! doesn't work, in fact I agree it makes it worse. Good luck getting readability with that. Ultimately, something else needs to be developed. Perhaps a character we can use in alongside each item on the type declaration, or we need to be able to hit the whole line in one blow.. Just my penny.I'm not sure what this is meant to convey. In any language with type constructor you are able to construct long, incomprehensible types. You don't need storage classes and qualifiers for that. Andrei
Mar 16 2007
On Fri, 16 Mar 2007 14:05:17 -0700, Andrei Alexandrescu (See Website For Email) wrote:Dan wrote:It is trying to convey the difficultly in determining which 'final'/'const'/'super const' instance refers to which part of the declaration. Given ... int[int**][]*[char[]][3][17][3,17]* x; and I want to make the 'x' immutable and the 'char[]' immutable, how does one write the declaration? Where does one place the 'final'/'const'/'super const' and where do the parenthesis go? -- Derek Parnell Melbourne, Australia "Justice for David Hicks!" skype: derek.j.parnellWow... I've never put this much thought into const/final stuff. Ultimately, the program *cannot* prevent data in memory from being changed. It can at best prevent you from accidentally changing it; hence final and const declarations mean "I don't want anyone to change these, can you raise an error if someone tries to within D?" Also, the problem breaks down to 'what am I declaring const?'. If I declare: const int* x; // is it the pointer, or the int? This doesn't seem important until you get to: const int[int**][]* x; // now what is it? Ultimately, you have this problem going through each and every pointer, array and value. You could theoretically write this: const int[int**][]*[char[]][3][17][3,17]* x; and now what are you going to do? declare it: final const final final const const final final final final final const? Even final const! super const! final! const! doesn't work, in fact I agree it makes it worse. Good luck getting readability with that. Ultimately, something else needs to be developed. Perhaps a character we can use in alongside each item on the type declaration, or we need to be able to hit the whole line in one blow.. Just my penny.I'm not sure what this is meant to convey.
Mar 16 2007
Derek Parnell wrote:On Fri, 16 Mar 2007 14:05:17 -0700, Andrei Alexandrescu (See Website For Email) wrote:final int[int**][]*[const char[]][3][17][3,17]* x; AndreiDan wrote:It is trying to convey the difficultly in determining which 'final'/'const'/'super const' instance refers to which part of the declaration. Given ... int[int**][]*[char[]][3][17][3,17]* x; and I want to make the 'x' immutable and the 'char[]' immutable, how does one write the declaration? Where does one place the 'final'/'const'/'super const' and where do the parenthesis go?Wow... I've never put this much thought into const/final stuff. Ultimately, the program *cannot* prevent data in memory from being changed. It can at best prevent you from accidentally changing it; hence final and const declarations mean "I don't want anyone to change these, can you raise an error if someone tries to within D?" Also, the problem breaks down to 'what am I declaring const?'. If I declare: const int* x; // is it the pointer, or the int? This doesn't seem important until you get to: const int[int**][]* x; // now what is it? Ultimately, you have this problem going through each and every pointer, array and value. You could theoretically write this: const int[int**][]*[char[]][3][17][3,17]* x; and now what are you going to do? declare it: final const final final const const final final final final final const? Even final const! super const! final! const! doesn't work, in fact I agree it makes it worse. Good luck getting readability with that. Ultimately, something else needs to be developed. Perhaps a character we can use in alongside each item on the type declaration, or we need to be able to hit the whole line in one blow.. Just my penny.I'm not sure what this is meant to convey.
Mar 16 2007
Derek Parnell wrote:Given ... int[int**][]*[char[]][3][17][3,17]* x; and I want to make the 'x' immutable and the 'char[]' immutable, how does one write the declaration? Where does one place the 'final'/'const'/'super const' and where do the parenthesis go?final int[int**][]*[ const(char[]) ][3][17][3,17]* x;
Mar 16 2007
Walter Bright wrote:Derek Parnell wrote:Hmm... I think either one of you (Walter and Andrei) got bitten by the "you have to put parens around the type or it'll get final'ed, too" thing, or one of you got bitten by the "is this going to make it final? Jeeze, I dunno; better put parens in just in case." This makes me somewhat worried :P -- Daniel -- Unlike Knuth, I have neither proven or tried the above; it may not even make sense. v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/Given ... int[int**][]*[char[]][3][17][3,17]* x; and I want to make the 'x' immutable and the 'char[]' immutable, how does one write the declaration? Where does one place the 'final'/'const'/'super const' and where do the parenthesis go?final int[int**][]*[ const(char[]) ][3][17][3,17]* x;
Mar 16 2007
Daniel Keep wrote:Walter Bright wrote:No, in this context the parens would be simply optional. Only when const occurs at top level it will engulf the symbol too. AndreiDerek Parnell wrote:Hmm... I think either one of you (Walter and Andrei) got bitten by the "you have to put parens around the type or it'll get final'ed, too" thing, or one of you got bitten by the "is this going to make it final? Jeeze, I dunno; better put parens in just in case."Given ... int[int**][]*[char[]][3][17][3,17]* x; and I want to make the 'x' immutable and the 'char[]' immutable, how does one write the declaration? Where does one place the 'final'/'const'/'super const' and where do the parenthesis go?final int[int**][]*[ const(char[]) ][3][17][3,17]* x;
Mar 16 2007
On Fri, 16 Mar 2007 15:54:26 -0700, Walter Bright wrote:Derek Parnell wrote:Are you serious???? I want 'x' to be immutable so I need to use 'final' and place it the furtherest away from what is is qualifying. I want 'char[]' to be immutable so I must use 'const' and place it next to what it is qualifying plus use parenthesis around its target too. Why do you think that this is intuitive, consistent, and easy to read? -- Derek Parnell Melbourne, Australia "Justice for David Hicks!" skype: derek.j.parnellGiven ... int[int**][]*[char[]][3][17][3,17]* x; and I want to make the 'x' immutable and the 'char[]' immutable, how does one write the declaration? Where does one place the 'final'/'const'/'super const' and where do the parenthesis go?final int[int**][]*[ const(char[]) ][3][17][3,17]* x;
Mar 17 2007
Derek Parnell wrote:On Fri, 16 Mar 2007 15:54:26 -0700, Walter Bright wrote:Or you want it to be static: static int[int**][]*[char[]][3][17][3,17]* x; Or you want it to be private: private int[int**][]*[char[]][3][17][3,17]* x; Or deprecated: deprecated int[int**][]*[char[]][3][17][3,17]* x; In all cases, you place the attribute the furthest away from what it qualifies. It's quite standard in C-family languages, including D, as I'm sure you know. I don't see why "final"/"const"/"super const" should be any different.Derek Parnell wrote:Are you serious???? I want 'x' to be immutable so I need to use 'final' and place it the furtherest away from what is is qualifying.Given ... int[int**][]*[char[]][3][17][3,17]* x; and I want to make the 'x' immutable and the 'char[]' immutable, how does one write the declaration? Where does one place the 'final'/'const'/'super const' and where do the parenthesis go?final int[int**][]*[ const(char[]) ][3][17][3,17]* x;I want 'char[]' to be immutable so I must use 'const' and place it next to what it is qualifying plus use parenthesis around its target too.You need it within the same "scope" as the char[]: inside the [] where the char[] is.Why do you think that this is intuitive, consistent, and easy to read?What makes you think anything to do with a 35-character type is intuitive or easy to read? ;-) It's consistent enough for me. -- Remove ".doesnotlike.spam" from the mail address.
Mar 17 2007
Derek Parnell wrote:On Fri, 16 Mar 2007 15:54:26 -0700, Walter Bright wrote:Because you didn't suggest a better design. :o) AndreiDerek Parnell wrote:Are you serious???? I want 'x' to be immutable so I need to use 'final' and place it the furtherest away from what is is qualifying. I want 'char[]' to be immutable so I must use 'const' and place it next to what it is qualifying plus use parenthesis around its target too. Why do you think that this is intuitive, consistent, and easy to read?Given ... int[int**][]*[char[]][3][17][3,17]* x; and I want to make the 'x' immutable and the 'char[]' immutable, how does one write the declaration? Where does one place the 'final'/'const'/'super const' and where do the parenthesis go?final int[int**][]*[ const(char[]) ][3][17][3,17]* x;
Mar 17 2007
Dan wrote:Wow... I've never put this much thought into const/final stuff. Ultimately, the program *cannot* prevent data in memory from being changed. It can at best prevent you from accidentally changing it; hence final and const declarations mean "I don't want anyone to change these, can you raise an error if someone tries to within D?" Also, the problem breaks down to 'what am I declaring const?'. If I declare: const int* x; // is it the pointer, or the int? This doesn't seem important until you get to: const int[int**][]* x; // now what is it? Ultimately, you have this problem going through each and every pointer, array and value. You could theoretically write this: const int[int**][]*[char[]][3][17][3,17]* x; and now what are you going to do? declare it: final const final final const const final final final final final const? Even final const! super const! final! const! doesn't work, in fact I agree it makes it worse. Good luck getting readability with that.This: const int[int**][]*[char[]][3][17][3,17]* x; is *already* unreadable (plus I don't think that [3,17] part is legal D). If any reasonable programmer really did have a need for such a type then they would probably break it up into aliases with some sort of meaning. --bb
Mar 16 2007
Bill Baxter wrote:This: const int[int**][]*[char[]][3][17][3,17]* x; is *already* unreadable (plus I don't think that [3,17] part is legal D).--- $ cat test.d import std.stdio; void main() { int[3,17] x; writefln(typeid(typeof(x))); } $ dmd -run test.d int[17] --- http://www.digitalmars.com/d/expression.html#Expressions --- The left operand of the , is evaluated, then the right operand is evaluated. The type of the expression is the type of the right operand, and the result is the result of the right operand. --- This is mostly for C and C++ compatibility, AFAICT. There, it's typically used in macros that need it to perform multiple actions that can only be done in separate expressions, without having the macros expand to full statements. But it's also used in one of the multiply-evaluated clauses of a loop statement (for example, it can be used to increment multiple counters of a for loop on each iteration). It's also horribly abused as an overloaded operator in (amongst others) boost::lambda, where it replaces ';' for lambda expressions...
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Derek Parnell wrote:$ dmd -v1 With the v1 switch, I don't need to rewrite my code if it's already working and isn't being updated. And even if for some reason I do need to rewrite my code, I'm more than happy to do it in this case, if it gets us a sane, exception-free const system :) Heck, with D being as easy to parse as it is, I imagine that it wouldn't be terribly difficult for someone to write a source migration program; IIRC, Python actually had one of these for a particular version that broke several programs. Yeah, it's going to catch some people, but D !is Cpp, and there will always be things that are different. So long as these breaking changes are for the better, I can't imagine any reasonable person would complain[1]. -- Daniel [1]: Well, OK, they might complain anyway. But it's like how I could complain that my plans of doing car maintenance-related stuff has been ruined by this blasted wet weather! Considering that, as a country, we really need this sort of wet weather more often, and I know it, it's kinda an empty complaint :P -- Unlike Knuth, I have neither proven or tried the above; it may not even make sense. v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/But you are saying that if I don't want 'final', I not only have to avoid using 'final', I also have to put some of the phrase (and I know I'll never remember which parts) in parenthesis. But wait ... there's more. If I do want it to be 'final' all I have to do is not use the 'final' keyword. Am I getting this right? Is it not possible to make reading code simple?An intuition that I see reasonable is that const by default engulfs everything to its right: const char[] str = "Hi!"; // same as const(char[] str) = "Hi!"; When it engulfs the symbol, it makes it immutable, hence final. So by putting the parens you limit const's power. But I'd be glad to drop this exception. I'm not sure what Walter and people who'll have to modify their code would say though. ... Andrei
Mar 16 2007
Daniel Keep wrote:$ dmd -v1 With the v1 switch, I don't need to rewrite my code if it's already working and isn't being updated. And even if for some reason I do need to rewrite my code, I'm more than happy to do it in this case, if it gets us a sane, exception-free const system :) Heck, with D being as easy to parse as it is, I imagine that it wouldn't be terribly difficult for someone to write a source migration program; IIRC, Python actually had one of these for a particular version that broke several programs.The python Numpy project has that too. There have been a lot of changes from the old version of numpy called Numeric, but you can fix almost all of the common cases using a script that comes with Numpy. I suspect the script to upgrade D code would be much much MUCH simpler than that.Yeah, it's going to catch some people, but D !is Cpp, and there will always be things that are different. So long as these breaking changes are for the better, I can't imagine any reasonable person would complain[1].[1]: Well, OK, they might complain anyway. But it's like how I could complain that my plans of doing car maintenance-related stuff has been ruined by this blasted wet weather! Considering that, as a country, we really need this sort of wet weather more often, and I know it, it's kinda an empty complaint :PGreat analogy. --bb
Mar 16 2007
Andrei Alexandrescu (See Website For Email) Wrote:Derek Parnell wrote:<snip>On Fri, 16 Mar 2007 02:25:24 -0700, Andrei Alexandrescu (See Website For Email) wrote:I was just trying to minimize the amount of broken code. Also, we<snip>An intuition that I see reasonable is that const by default engulfs everything to its right: const char[] str = "Hi!"; // same as const(char[] str) = "Hi!"; When it engulfs the symbol, it makes it immutable, hence final. So by putting the parens you limit const's power. But I'd be glad to drop this exception. I'm not sure what Walter and people who'll have to modify their code would say though.<snip>Ok, this maybe somewhat selfish since I haven't used D's 'const' much, but I really have to agree with Derek -- the exceptions need to be dropped <g> Based on past NG discussions on 'const', I believe it is so important to get this right the first time that the exceptions need to be removed in favor of the most intuitive and consistent syntax. Since the current "const char[] str = 'XYZ'"; semantics would prevent both str or its elements from being modified, we could make a reasonable assumption that code already properly tested and running (and just recompiled with a new compiler) would not break anyhow, correct? Thanks, - DaveThe EXCEPTION (alarms still ringing) seems to be saying that 'const char[] X' means that X.ptr, X.length and the data in X's RAM cannot be changed.I am hearing it. :o)
Mar 23 2007
Dave wrote:Ok, this maybe somewhat selfish since I haven't used D's 'const' much, but I really have to agree with Derek -- the exceptions need to be dropped <g> Based on past NG discussions on 'const', I believe it is so important to get this right the first time that the exceptions need to be removed in favor of the most intuitive and consistent syntax. Since the current "const char[] str = 'XYZ'"; semantics would prevent both str or its elements from being modified, we could make a reasonable assumption that code already properly tested and running (and just recompiled with a new compiler) would not break anyhow, correct?I think this is a valid point. Andrei
Mar 23 2007
Andrei Alexandrescu (See Website For Email) Wrote:Dave wrote:Maybe a few more justifications for getting rid of the exceptions: - It's more effort and complexity to add the exceptions to the compiler, docs., etc... - IIUC, a search-and-replace operation from 'const' to 'final' or 'final const' could 'fix' most current source code. - It would be better to have to add the exceptions later (based on programmer feedback) than to add them and then have to remove them. - The other case you mentioned (i.e.: const real MyPI = 3.14159;) should not be a problem with most currently correct D code (like const char[] str = "XYZ"; above). Could this case (a value type constant) warrant an error with the new compiler? Thanks, - DaveOk, this maybe somewhat selfish since I haven't used D's 'const' much, but I really have to agree with Derek -- the exceptions need to be dropped <g> Based on past NG discussions on 'const', I believe it is so important to get this right the first time that the exceptions need to be removed in favor of the most intuitive and consistent syntax. Since the current "const char[] str = 'XYZ'"; semantics would prevent both str or its elements from being modified, we could make a reasonable assumption that code already properly tested and running (and just recompiled with a new compiler) would not break anyhow, correct?I think this is a valid point.
Mar 24 2007
Andrei Alexandrescu (See Website For Email) wrote:Bruno Medeiros wrote:Does this last category include some of the current use of D const -- a value which is not modifiable, *even in theory*, and may not even have any run-time existence at all -- the C equivalent being a #defined constant. IMHO (b) should be 'readonly' and (c) should be 'const'. But this may be because I'm a physicist, and for me a constant is something like the speed of light, and C++'s const_cast always seemed utterly nonsensical. void alabama() { // Actually compiles! Someone should be shot for this. const double PI = 3.14159265358; *const_cast<double *>(&PI) = 4.0; } Whereas 'readonly' seems to be a much better match for (b). Although it's an extra keyword, it seems to me that the concept discussed here is sufficiently fundamental to justify an extra keyword. Especially if we have a chance to rid of 'lazy'.What is the status of the experimental designs for the "storage classes" manipulation that Andrei and others where thinking of for D. The last I heard from it was Andrei's max suggestion from his max design challenge, however, I think that suggestion may suffer from some problems in regards to the "maxtype" requirement, plus it is wholly incomplete in regards to how storage classes interact between each other. Like Andrei said, what is a "const inout lazy const char[]", if valid at all? Is there any news here? Is there a working(aka complete) design?We have talked about a design. In short, the intent is to define three flavors of immutability: a) final - a simple storage class controlling the immutability of the bits allocated for the symbol per se; b) const - type qualifier meaning an immutable view of an otherwise modifiable data. const does not control the bits of the object, only the storage addressed indirectly by it (transitively); c) "superconst" - denoted as "const!" or "super const": type qualifier meaning that the data is genuinely unmodifiable.
Mar 16 2007
Don Clugston wrote:Andrei Alexandrescu (See Website For Email) wrote:Presumably this can also be an immutable view of immutable (case c) data?Bruno Medeiros wrote:What is the status of the experimental designs for the "storage classes" manipulation that Andrei and others where thinking of for D. The last I heard from it was Andrei's max suggestion from his max design challenge, however, I think that suggestion may suffer from some problems in regards to the "maxtype" requirement, plus it is wholly incomplete in regards to how storage classes interact between each other. Like Andrei said, what is a "const inout lazy const char[]", if valid at all? Is there any news here? Is there a working(aka complete) design?We have talked about a design. In short, the intent is to define three flavors of immutability: a) final - a simple storage class controlling the immutability of the bits allocated for the symbol per se; b) const - type qualifier meaning an immutable view of an otherwise modifiable data. const does not control the bits of the object, only the storage addressed indirectly by it (transitively);[snip]c) "superconst" - denoted as "const!" or "super const": type qualifier meaning that the data is genuinely unmodifiable.Does this last category include some of the current use of D const -- a value which is not modifiable, *even in theory*, and may not even have any run-time existence at all -- the C equivalent being a #defined constant. IMHO (b) should be 'readonly' and (c) should be 'const'.Whereas 'readonly' seems to be a much better match for (b). Although it's an extra keyword, it seems to me that the concept discussed here is sufficiently fundamental to justify an extra keyword. Especially if we have a chance to rid of 'lazy'.vote++; 'const' should really means "constant". A new keyword is more than justified here.
Mar 16 2007
IMHO (b) should be 'readonly' and (c) should be 'const'.[snip] vote++ Keywords -------- I also think keywords can be written attached to one another. Like if you were to really call it "super const" have it called superconst instead of super_const. It is like the foreach_reverse that we have in D. Why not call it foreachreverse instead. I mean we don't write for_each() { } but we write foreach() { } const! is ugly.
Mar 16 2007
sclytrack wrote:Yet you write static const not staticconst; public static not publicstatic; static if and not staticif; and so on. superconst came up too. But it creates a bad precedent. A healthier precedent is to synthesize phrases, not new keywords, from the existing keywords. Think of "static if" or "final switch". Very beautiful.IMHO (b) should be 'readonly' and (c) should be 'const'.[snip] vote++ Keywords -------- I also think keywords can be written attached to one another. Like if you were to really call it "super const" have it called superconst instead of super_const.It is like the foreach_reverse that we have in D. Why not call it foreachreverse instead.Probably it's best to call it foreach reverse. It's unambiguous, easy to parse, does not add new keywords, and continues another nice precedent set by extern(language) and by scope(exit). Andrei
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:sclytrack wrote:So you mean foreach(reverse) then? I do like that! You're right that it is quite D-like. Too bad you weren't around back when foreach_reverse was introduced? ;-) --bbYet you write static const not staticconst; public static not publicstatic; static if and not staticif; and so on. superconst came up too. But it creates a bad precedent. A healthier precedent is to synthesize phrases, not new keywords, from the existing keywords. Think of "static if" or "final switch". Very beautiful.IMHO (b) should be 'readonly' and (c) should be 'const'.[snip] vote++ Keywords -------- I also think keywords can be written attached to one another. Like if you were to really call it "super const" have it called superconst instead of super_const.It is like the foreach_reverse that we have in D. Why not call it foreachreverse instead.Probably it's best to call it foreach reverse. It's unambiguous, easy to parse, does not add new keywords, and continues another nice precedent set by extern(language) and by scope(exit).
Mar 16 2007
Bill Baxter wrote:So you mean foreach(reverse) then? I do like that! You're right that it is quite D-like. Too bad you weren't around back when foreach_reverse was introduced? ;-)This actually came up in more general terms: http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D.announce&artnum=5015 Perhaps I over-complicated it with the talk of parallelism, but the idea was still there :-) Sean
Mar 16 2007
Sean Kelly wrote:Bill Baxter wrote:You have it using foreach!(arg) syntax there. But it's not really a template. Maybe it could be, and if it were then that would be great syntax for it. But otherwise it's just unprecendented. A new special case. But what Andrei points out is that there are two precedents for the keyword(subkeyword) syntax, where the possible subkeywords are pre-defined by the compiler and completely change the behavior of the keyword, or rather select very different behaviors all under the same general umbrella. It's exactly what was needed for foreach and foreach_reverse. --bbSo you mean foreach(reverse) then? I do like that! You're right that it is quite D-like. Too bad you weren't around back when foreach_reverse was introduced? ;-)This actually came up in more general terms: http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D. nnounce&artnum=5015 Perhaps I over-complicated it with the talk of parallelism, but the idea was still there :-)
Mar 16 2007
Bill Baxter wrote:Sean Kelly wrote:The syntax isn't really important. I was mostly looking for a way to avoid creating a new keyword while supporting multi-directional iteration. SeanBill Baxter wrote:You have it using foreach!(arg) syntax there. But it's not really a template. Maybe it could be, and if it were then that would be great syntax for it. But otherwise it's just unprecendented. A new special case.So you mean foreach(reverse) then? I do like that! You're right that it is quite D-like. Too bad you weren't around back when foreach_reverse was introduced? ;-)This actually came up in more general terms: http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D. nnounce&artnum=5015 Perhaps I over-complicated it with the talk of parallelism, but the idea was still there :-)
Mar 16 2007
Bill Baxter wrote:Andrei Alexandrescu (See Website For Email) wrote:Possibly even without the parens: foreach (i ; array) { ... } foreach reverse (i ; array) { ... } I have a feeling Walter is unlikely to change that though :o). Andreisclytrack wrote:So you mean foreach(reverse) then? I do like that! You're right that it is quite D-like. Too bad you weren't around back when foreach_reverse was introduced? ;-)Yet you write static const not staticconst; public static not publicstatic; static if and not staticif; and so on. superconst came up too. But it creates a bad precedent. A healthier precedent is to synthesize phrases, not new keywords, from the existing keywords. Think of "static if" or "final switch". Very beautiful.IMHO (b) should be 'readonly' and (c) should be 'const'.[snip] vote++ Keywords -------- I also think keywords can be written attached to one another. Like if you were to really call it "super const" have it called superconst instead of super_const.It is like the foreach_reverse that we have in D. Why not call it foreachreverse instead.Probably it's best to call it foreach reverse. It's unambiguous, easy to parse, does not add new keywords, and continues another nice precedent set by extern(language) and by scope(exit).
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Bill Baxter wrote:Except then 'reverse' would have to be a keyword too, no? Or would you do away with parens in the extern and scope cases too? I liked the suggestion because it makes foreach and its reverse variant less of a special case. scope and extern can be followed by things that that are keyword-like but that specify a specific variation of the keyword. Likewise, foreach would be the same. But if you're going to special case foreach in the end anyway, I see little point. It would also open the door for some sort of foreach(parallel) construct without having to introduce yet another underscored keyword with double-digit character count. --bbAndrei Alexandrescu (See Website For Email) wrote:Possibly even without the parens: foreach (i ; array) { ... } foreach reverse (i ; array) { ... } I have a feeling Walter is unlikely to change that though :o). Andreisclytrack wrote:So you mean foreach(reverse) then? I do like that! You're right that it is quite D-like. Too bad you weren't around back when foreach_reverse was introduced? ;-)Yet you write static const not staticconst; public static not publicstatic; static if and not staticif; and so on. superconst came up too. But it creates a bad precedent. A healthier precedent is to synthesize phrases, not new keywords, from the existing keywords. Think of "static if" or "final switch". Very beautiful.IMHO (b) should be 'readonly' and (c) should be 'const'.[snip] vote++ Keywords -------- I also think keywords can be written attached to one another. Like if you were to really call it "super const" have it called superconst instead of super_const.It is like the foreach_reverse that we have in D. Why not call it foreachreverse instead.Probably it's best to call it foreach reverse. It's unambiguous, easy to parse, does not add new keywords, and continues another nice precedent set by extern(language) and by scope(exit).
Mar 16 2007
Bill Baxter wrote:Andrei Alexandrescu (See Website For Email) wrote:I think the theory is that, like scope(exit), where the 'exit' is not really a keyword, in the foreach xyz (...) {...} expression, there is no legal token that can go where 'xyz' is, so something there doesn't need to be special. You could use "i" or "main" without conflicting with a variable or function name, for instance, because those can't appear there. It's only in places where a user-defined identifier is legal that a given 'adjective' word needs to be keywords. You could define this: if and only if () {} while away the hours () {} ... and not conflict with existing variables named (and, only, away, the, hours). KevinBill Baxter wrote:Except then 'reverse' would have to be a keyword too, no?Andrei Alexandrescu (See Website For Email) wrote:Possibly even without the parens: foreach (i ; array) { ... } foreach reverse (i ; array) { ... } I have a feeling Walter is unlikely to change that though :o). Andreisclytrack wrote:So you mean foreach(reverse) then? I do like that! You're right that it is quite D-like. Too bad you weren't around back when foreach_reverse was introduced? ;-)Yet you write static const not staticconst; public static not publicstatic; static if and not staticif; and so on. superconst came up too. But it creates a bad precedent. A healthier precedent is to synthesize phrases, not new keywords, from the existing keywords. Think of "static if" or "final switch". Very beautiful.IMHO (b) should be 'readonly' and (c) should be 'const'.[snip] vote++ Keywords -------- I also think keywords can be written attached to one another. Like if you were to really call it "super const" have it called superconst instead of super_const.It is like the foreach_reverse that we have in D. Why not call it foreachreverse instead.Probably it's best to call it foreach reverse. It's unambiguous, easy to parse, does not add new keywords, and continues another nice precedent set by extern(language) and by scope(exit).--bb
Mar 21 2007
Andrei Alexandrescu (See Website For Email) wrote:sclytrack wrote:How about the '1984' syntax? double + const int; // very very const double + super(); // call parent-of-parent constructor (just kidding!) I've read the description of the three const types and it's not clear to me which is which. It seems like being "immutable per se" (final) and "genuinely unmodifiable" are pretty much synonymous. This may seem backwards, but it would help me to keep them apart if I knew how they were implemented (semantically, not necessarily in terms of code generation). As I understand it, "const" means "readonly view of something", similar to C++'s const but without the big "disable me" button. The data is live but "under glass". "final const" means the compiler never generates code to modify the underlying data and can assume (cache, do constant folding on) the underlying data. Almost like a #define, except that you can take the address of it. "invariant" is just like const, but refers to the symbol (and by extension the data) rather than just the data. I'm guessing that volatile only affects const. An invariant object doesn't need it and a 'final' is also essentially compile time foldable and thus might not even be loaded from memory per se. (Eventually, and subject to quality of implementation, etc.) But before/after a volatile block, a normal "const" might need to be refreshed from memory in case someone else had updated? (Feel free to tell me that some of this has been answered, and I'll look over the thread again.) KevinYet you write static const not staticconst; public static not publicstatic; static if and not staticif; and so on. superconst came up too. But it creates a bad precedent. A healthier precedent is to synthesize phrases, not new keywords, from the existing keywords. Think of "static if" or "final switch". Very beautiful.IMHO (b) should be 'readonly' and (c) should be 'const'.[snip] vote++ Keywords -------- I also think keywords can be written attached to one another. Like if you were to really call it "super const" have it called superconst instead of super_const.It is like the foreach_reverse that we have in D. Why not call it foreachreverse instead.Probably it's best to call it foreach reverse. It's unambiguous, easy to parse, does not add new keywords, and continues another nice precedent set by extern(language) and by scope(exit). Andrei
Mar 21 2007
Kevin Bealer wrote:As I understand it, "const" means "readonly view of something", similar to C++'s const but without the big "disable me" button. The data is live but "under glass". "final const" means the compiler never generates code to modify the underlying data and can assume (cache, do constant folding on) the underlying data. Almost like a #define, except that you can take the address of it. "invariant" is just like const, but refers to the symbol (and by extension the data) rather than just the data.Swap these two names. Andrei
Mar 21 2007
Kevin Bealer wrote:Andrei Alexandrescu (See Website For Email) wrote:Disclaimer: My current best understanding. Final -> You may not re-bind/re-assign to this symbol. The data bound to this symbol (ie, the object, struct, array, etc) is fully mutable. Its a storage class of the variable, and has no effect on the data itself. Foldable if its value is a basic scalar, such as an int. Const -> Part of the type, provides a read-only view into data owned by code elsewhere with a mutable referance. Invariant -> Part of the type, guaranteed absolutely not to change. Essentially a contract of sorts.. in fact, I'm starting to think of it as an invariant{} contract block which "simply" asserts the data is always in the same state as immediately after construction. Side effects of combinations: 'final const' -> An unbindable read-only view. Could be useful for passing read-only views of data by referance, ie: void foo (final const ref bar) -- foo cannot modify the data referanced by bar, nor can it reassign bar, which would've reassigned the original variable since its by ref. (The data referanced is constant, the referance itself -- ie the symbol -- is not.) 'final invariant' -> Ultimate const'ness. An unbindable variable whose value is a referance to unchanging data. Man I can't wait for all this to finally ship, in the hopes that it will come along with a thorough user manual... -- Chris Nicholson-Saulssclytrack wrote:How about the '1984' syntax? double + const int; // very very const double + super(); // call parent-of-parent constructor (just kidding!) I've read the description of the three const types and it's not clear to me which is which. It seems like being "immutable per se" (final) and "genuinely unmodifiable" are pretty much synonymous. This may seem backwards, but it would help me to keep them apart if I knew how they were implemented (semantically, not necessarily in terms of code generation). As I understand it, "const" means "readonly view of something", similar to C++'s const but without the big "disable me" button. The data is live but "under glass". "final const" means the compiler never generates code to modify the underlying data and can assume (cache, do constant folding on) the underlying data. Almost like a #define, except that you can take the address of it. "invariant" is just like const, but refers to the symbol (and by extension the data) rather than just the data. I'm guessing that volatile only affects const. An invariant object doesn't need it and a 'final' is also essentially compile time foldable and thus might not even be loaded from memory per se. (Eventually, and subject to quality of implementation, etc.) But before/after a volatile block, a normal "const" might need to be refreshed from memory in case someone else had updated? (Feel free to tell me that some of this has been answered, and I'll look over the thread again.) KevinYet you write static const not staticconst; public static not publicstatic; static if and not staticif; and so on. superconst came up too. But it creates a bad precedent. A healthier precedent is to synthesize phrases, not new keywords, from the existing keywords. Think of "static if" or "final switch". Very beautiful.IMHO (b) should be 'readonly' and (c) should be 'const'.[snip] vote++ Keywords -------- I also think keywords can be written attached to one another. Like if you were to really call it "super const" have it called superconst instead of super_const.It is like the foreach_reverse that we have in D. Why not call it foreachreverse instead.Probably it's best to call it foreach reverse. It's unambiguous, easy to parse, does not add new keywords, and continues another nice precedent set by extern(language) and by scope(exit). Andrei
Mar 22 2007
Frits van Bommel wrote:Don Clugston wrote:Yes, super const is trivially convertible to const. Const alone really means "I don't care about the nature of the data, I just promise I have no business writing into it".Andrei Alexandrescu (See Website For Email) wrote:Presumably this can also be an immutable view of immutable (case c) data?Bruno Medeiros wrote:What is the status of the experimental designs for the "storage classes" manipulation that Andrei and others where thinking of for D. The last I heard from it was Andrei's max suggestion from his max design challenge, however, I think that suggestion may suffer from some problems in regards to the "maxtype" requirement, plus it is wholly incomplete in regards to how storage classes interact between each other. Like Andrei said, what is a "const inout lazy const char[]", if valid at all? Is there any news here? Is there a working(aka complete) design?We have talked about a design. In short, the intent is to define three flavors of immutability: a) final - a simple storage class controlling the immutability of the bits allocated for the symbol per se; b) const - type qualifier meaning an immutable view of an otherwise modifiable data. const does not control the bits of the object, only the storage addressed indirectly by it (transitively);We're doomed either way. We don't want to confuse C++ programmers. Two levels of strength of const are more descriptive than a new keyword that half of the people will think it's the other way. Andrei[snip]c) "superconst" - denoted as "const!" or "super const": type qualifier meaning that the data is genuinely unmodifiable.Does this last category include some of the current use of D const -- a value which is not modifiable, *even in theory*, and may not even have any run-time existence at all -- the C equivalent being a #defined constant. IMHO (b) should be 'readonly' and (c) should be 'const'.Whereas 'readonly' seems to be a much better match for (b). Although it's an extra keyword, it seems to me that the concept discussed here is sufficiently fundamental to justify an extra keyword. Especially if we have a chance to rid of 'lazy'.vote++; 'const' should really means "constant". A new keyword is more than justified here.
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:We're doomed either way. We don't want to confuse C++ programmers. Two levels of strength of const are more descriptive than a new keyword that half of the people will think it's the other way.True. If we have readonly and const, I expect endless confusion about which is which.
Mar 16 2007
Walter Bright wrote:Andrei Alexandrescu (See Website For Email) wrote:Not to mention if you also have 'readsometimes'. Nobody'll EVER figure that one out :) --benjiWe're doomed either way. We don't want to confuse C++ programmers. Two levels of strength of const are more descriptive than a new keyword that half of the people will think it's the other way.True. If we have readonly and const, I expect endless confusion about which is which.
Mar 16 2007
Don Clugston wrote:Andrei Alexandrescu (See Website For Email) wrote:Yes.Bruno Medeiros wrote:Does this last category include some of the current use of D const -- a value which is not modifiable, *even in theory*, and may not even have any run-time existence at all -- the C equivalent being a #defined constant.What is the status of the experimental designs for the "storage classes" manipulation that Andrei and others where thinking of for D. The last I heard from it was Andrei's max suggestion from his max design challenge, however, I think that suggestion may suffer from some problems in regards to the "maxtype" requirement, plus it is wholly incomplete in regards to how storage classes interact between each other. Like Andrei said, what is a "const inout lazy const char[]", if valid at all? Is there any news here? Is there a working(aka complete) design?We have talked about a design. In short, the intent is to define three flavors of immutability: a) final - a simple storage class controlling the immutability of the bits allocated for the symbol per se; b) const - type qualifier meaning an immutable view of an otherwise modifiable data. const does not control the bits of the object, only the storage addressed indirectly by it (transitively); c) "superconst" - denoted as "const!" or "super const": type qualifier meaning that the data is genuinely unmodifiable.IMHO (b) should be 'readonly' and (c) should be 'const'. But this may be because I'm a physicist, and for me a constant is something like the speed of light, and C++'s const_cast always seemed utterly nonsensical. void alabama() { // Actually compiles! Someone should be shot for this. const double PI = 3.14159265358; *const_cast<double *>(&PI) = 4.0; } Whereas 'readonly' seems to be a much better match for (b). Although it's an extra keyword, it seems to me that the concept discussed here is sufficiently fundamental to justify an extra keyword. Especially if we have a chance to rid of 'lazy'.If we get rid of lazy, I'll sacrifice a lamb :o). We've shoved keywords like "readonly" and "view" for a while, and they just added more confusion than cleared, at a high cost. If (as I suspect) super const appears relatively infrequently, it might be fine to just encode it as the mildly verbose "super const". In fact, it's shorter than "keepyourgrubbyhandsoff". :o) Andrei
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Don Clugston wrote:My problem is, I don't see any connection between "don't touch" and "constant" except that C++ got them confused. In every other other context outside of C++, "constant" means "it will not change". Mathematically, you can "hold something constant" (even though it is actually a variable), but as long as it is being held constant, it can't change. Suppose in a function, you have 'const' access to a global variable. Another thread with write-access to that variable can change it, while the function is executing. It makes sense for a function to have read-only access to a variable, and need to obtain a mutex when it wants to obtain the current value. But that's not a constant in any reasonable sense of the word. Don.Andrei Alexandrescu (See Website For Email) wrote:Yes.Bruno Medeiros wrote:Does this last category include some of the current use of D const -- a value which is not modifiable, *even in theory*, and may not even have any run-time existence at all -- the C equivalent being a #defined constant.What is the status of the experimental designs for the "storage classes" manipulation that Andrei and others where thinking of for D. The last I heard from it was Andrei's max suggestion from his max design challenge, however, I think that suggestion may suffer from some problems in regards to the "maxtype" requirement, plus it is wholly incomplete in regards to how storage classes interact between each other. Like Andrei said, what is a "const inout lazy const char[]", if valid at all? Is there any news here? Is there a working(aka complete) design?We have talked about a design. In short, the intent is to define three flavors of immutability: a) final - a simple storage class controlling the immutability of the bits allocated for the symbol per se; b) const - type qualifier meaning an immutable view of an otherwise modifiable data. const does not control the bits of the object, only the storage addressed indirectly by it (transitively); c) "superconst" - denoted as "const!" or "super const": type qualifier meaning that the data is genuinely unmodifiable.IMHO (b) should be 'readonly' and (c) should be 'const'. But this may be because I'm a physicist, and for me a constant is something like the speed of light, and C++'s const_cast always seemed utterly nonsensical. void alabama() { // Actually compiles! Someone should be shot for this. const double PI = 3.14159265358; *const_cast<double *>(&PI) = 4.0; } Whereas 'readonly' seems to be a much better match for (b). Although it's an extra keyword, it seems to me that the concept discussed here is sufficiently fundamental to justify an extra keyword. Especially if we have a chance to rid of 'lazy'.If we get rid of lazy, I'll sacrifice a lamb :o). We've shoved keywords like "readonly" and "view" for a while, and they just added more confusion than cleared, at a high cost. If (as I suspect) super const appears relatively infrequently, it might be fine to just encode it as the mildly verbose "super const". In fact, it's shorter than "keepyourgrubbyhandsoff". :o) Andrei
Mar 16 2007
Don Clugston wrote:My problem is, I don't see any connection between "don't touch" and "constant" except that C++ got them confused. In every other other context outside of C++, "constant" means "it will not change". Mathematically, you can "hold something constant" (even though it is actually a variable), but as long as it is being held constant, it can't change. Suppose in a function, you have 'const' access to a global variable. Another thread with write-access to that variable can change it, while the function is executing. It makes sense for a function to have read-only access to a variable, and need to obtain a mutex when it wants to obtain the current value. But that's not a constant in any reasonable sense of the word.The difference between math and computer memory is that all too often in the latter case you want to express modular separation very often. Modular separation (in this context) means that the right to modify a certain object is owned by some part of program, and other parts may be offered only a view of that memory. This is such an important concept, even C adopted it. All of C's library functions that take pointers are anontated in their signature to specify whether or not they modify their input or not. You want to enforce modular mutability cheaply. If D's immutability features fail to achieve that, we've done nothing. Andrei
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Don Clugston wrote:I don't think he's arguing against immutable views, just against calling it 'const' ;). In his words, from an earlier post: ===== Don Clugston wrote:My problem is, I don't see any connection between "don't touch" and "constant" except that C++ got them confused. In every other other context outside of C++, "constant" means "it will not change". Mathematically, you can "hold something constant" (even though it is actually a variable), but as long as it is being held constant, it can't change. Suppose in a function, you have 'const' access to a global variable. Another thread with write-access to that variable can change it, while the function is executing. It makes sense for a function to have read-only access to a variable, and need to obtain a mutex when it wants to obtain the current value. But that's not a constant in any reasonable sense of the word.The difference between math and computer memory is that all too often in the latter case you want to express modular separation very often. Modular separation (in this context) means that the right to modify a certain object is owned by some part of program, and other parts may be offered only a view of that memory. This is such an important concept, even C adopted it. All of C's library functions that take pointers are anontated in their signature to specify whether or not they modify their input or not. You want to enforce modular mutability cheaply. If D's immutability features fail to achieve that, we've done nothing.IMHO (b) should be 'readonly' and (c) should be 'const'. But this may be because I'm a physicist, and for me a constant is something like the speed of light, and C++'s const_cast always seemed utterly nonsensical. void alabama() { // Actually compiles! Someone should be shot for this. const double PI = 3.14159265358; *const_cast<double *>(&PI) = 4.0; } Whereas 'readonly' seems to be a much better match for (b). Although it's an extra keyword, it seems to me that the concept discussed here is sufficiently fundamental to justify an extra keyword. Especially if we have a chance to rid of 'lazy'.===== In fact, I think most people here will agree that the ability for a function to specify "I won't modify this" enforced by the compiler (modulo pointer casts etc.) is a good thing. Especially if, as you mentioned, the function can return an (im)mutable result depending on whether a parameter was (im)mutable without having to rewrite the function, since that seems to be the biggest annoyance about C++'s constness system.
Mar 16 2007
Frits van Bommel wrote:Andrei Alexandrescu (See Website For Email) wrote:Exactly. Thank you. I'm purely concerned about the name.Don Clugston wrote:I don't think he's arguing against immutable views, just against calling it 'const' ;).My problem is, I don't see any connection between "don't touch" and "constant" except that C++ got them confused. In every other other context outside of C++, "constant" means "it will not change". Mathematically, you can "hold something constant" (even though it is actually a variable), but as long as it is being held constant, it can't change. Suppose in a function, you have 'const' access to a global variable. Another thread with write-access to that variable can change it, while the function is executing. It makes sense for a function to have read-only access to a variable, and need to obtain a mutex when it wants to obtain the current value. But that's not a constant in any reasonable sense of the word.The difference between math and computer memory is that all too often in the latter case you want to express modular separation very often. Modular separation (in this context) means that the right to modify a certain object is owned by some part of program, and other parts may be offered only a view of that memory. This is such an important concept, even C adopted it. All of C's library functions that take pointers are anontated in their signature to specify whether or not they modify their input or not. You want to enforce modular mutability cheaply. If D's immutability features fail to achieve that, we've done nothing.
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:We've shoved keywords like "readonly" and "view" for a while, and they just added more confusion than cleared, at a high cost. If (as I suspect) super const appears relatively infrequently, it might be fine to just encode it as the mildly verbose "super const". In fact, it's shorter than "keepyourgrubbyhandsoff". :o) AndreiReally? I'd think super const would be used all the time. Anywhere a class has some invariant field, it'll probably be expressed as super const (if I'm understanding correctly that super const is the equivalent of #define constants in C++ or static final constants in Java). Let me join the ranks of those who hate both versions of the new syntax. const! looks either like a template or like "not const". You guys may think you're saving a keyword, and that might be technically correct from the perspective of the parser. But, for the perspective of the D developer, it still looks like you've introduced a new keyword, but it's a keyword that's A) nearly identical to another keyword, and B) contains a symbol. Ugh. I really. Really. Really. Hate it. Using "super const" is also annoying because all of the other storage classes use a single keyword. Now we've got this weird case that uses two keywords. And the word "super" is now overloaded in two completely unrelated concepts. (By the way, I don't like "static if" either. I think the right choice would have been #if, #foreach, etc. And I think C++ made a mistake by defining "long long" and "double double" types as well. Presumably, that saved some keywords, but we'd all have been better off if the types were defined as int8, int16, int32, int64, float32, float64, etc). I vote for "readonly" and "const". Anything else seems like a mistake. --benji
Mar 16 2007
Benji Smith wrote:And the word "super" is now overloaded in two completely unrelated concepts.Which isn't that rare, see the following link: http://www.prowiki.org/wiki4d/wiki.cgi?LanguageSpecification/KeywordIndex I find the following examples: auto, in, is, mixin, scope, static. I have come to abhor the keyword "static" largely due to the above. Too bad its various uses are unavoidably useful. <g> But I do agree with you, in a way. After writing the following I find my explanation somewhat unclear even to myself, but bear with me. The problem with "super const" is that "super" modifies the other keyword, "const", instead of saying something about the expression/statement/whatever (in this case, the type). Even "static", in all its horror, can be seen as specifying one of "module-level" or "compile-time". The other keywords mentioned above use their English meaning as such an explanation, and so can be understood without too much thought. "super const" would make "super" another "static": lacking context, you can't be sure about about even the general meaning, let alone the one in a specific instance. Upon reflection it may be moot, since one probably rarely cares about keywords' meanings without context, but I'm sure some psychologist could come up with something about intuitiveness which affects coding speed, or whatever. I'd be happiest to just get the feature as soon as possible; worrying about keyword semantics can come later. Just like the abominations beginning with "on_scope_". <g> -- Remove ".doesnotlike.spam" from the mail address.
Mar 16 2007
Deewiant wrote:Benji Smith wrote:Working in NLP myself, I totally disagree. Natural language is rife with homonimy and synonimy, and we're all very, very happy with that. But in this case we don't even have to go that far: "super" is an adjective meaning primarily "of high grade or quality" and qualifies a noun. If there's no noun, you don't know what is "of high grade or quality". It's a fact, and we don't even blink. The reality behind super const is that it expresses a stronger form of const. It makes a lot of sense if I dub it "super const" in natural language, to express it in the same way in the programming language. I thought that that's too verbose and devised "const!" as a shortcut (again with obvious conotations in natural language), but I'm thinking of dropping it and let type inference add "super" to "const" whenever it can. That should ensure exactness of the type system without verbosity in source code.And the word "super" is now overloaded in two completely unrelated concepts.Which isn't that rare, see the following link: http://www.prowiki.org/wiki4d/wiki.cgi?LanguageSpecification/KeywordIndex I find the following examples: auto, in, is, mixin, scope, static. I have come to abhor the keyword "static" largely due to the above. Too bad its various uses are unavoidably useful. <g> But I do agree with you, in a way. After writing the following I find my explanation somewhat unclear even to myself, but bear with me. The problem with "super const" is that "super" modifies the other keyword, "const", instead of saying something about the expression/statement/whatever (in this case, the type). Even "static", in all its horror, can be seen as specifying one of "module-level" or "compile-time". The other keywords mentioned above use their English meaning as such an explanation, and so can be understood without too much thought. "super const" would make "super" another "static": lacking context, you can't be sure about about even the general meaning, let alone the one in a specific instance. Upon reflection it may be moot, since one probably rarely cares about keywords' meanings without context, but I'm sure some psychologist could come up with something about intuitiveness which affects coding speed, or whatever.I'd be happiest to just get the feature as soon as possible; worrying about keyword semantics can come later. Just like the abominations beginning with "on_scope_". <g>Great idea. :o) Andrei
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Deewiant wrote:Oh, I didn't say I was of that opinion myself. In fact, I have a tendency to disagree with psychology in general. <g> You're right and that's good a point.The problem with "super const" is that "super" modifies the other keyword, "const", instead of saying something about the expression/statement/whatever (in this case, the type). Even "static", in all its horror, can be seen as specifying one of "module-level" or "compile-time". The other keywords mentioned above use their English meaning as such an explanation, and so can be understood without too much thought. "super const" would make "super" another "static": lacking context, you can't be sure about about even the general meaning, let alone the one in a specific instance. Upon reflection it may be moot, since one probably rarely cares about keywords' meanings without context, but I'm sure some psychologist could come up with something about intuitiveness which affects coding speed, or whatever.Working in NLP myself, I totally disagree. Natural language is rife with homonimy and synonimy, and we're all very, very happy with that. But in this case we don't even have to go that far: "super" is an adjective meaning primarily "of high grade or quality" and qualifies a noun. If there's no noun, you don't know what is "of high grade or quality". It's a fact, and we don't even blink.The reality behind super const is that it expresses a stronger form of const. It makes a lot of sense if I dub it "super const" in natural language, to express it in the same way in the programming language. I thought that that's too verbose and devised "const!" as a shortcut (again with obvious conotations in natural language), but I'm thinking of dropping it and let type inference add "super" to "const" whenever it can. That should ensure exactness of the type system without verbosity in source code."const!" has the advantage of being one word, but not really a new keyword. "super const" is two words. I still can't really express why I see that as a bad thing, but it _is_ better than adding a new keyword like "superconst" (or "keepyourgrubbyhandsoff"). I wouldn't be opposed to something like "readonly" though. Maybe I've just been coding too much Java recently: if I have to write "private final static double" much more I'm going to puke. <g> It's largely a question of what one's used to. Elsewhere in the thread the fact that some languages have "elsif" or "elif" or equivalent instead of "else if" was mentioned. I don't really see much of a difference, except that "elif" takes a bit too long to process for me since the "el" -> "else" relation isn't intuitive. But, just like an eventual "super const" (and the current "static"), coding enough in a language with such will make it intuitive to me, and I won't complain (much). In general, I do agree with your view, found elsewhere in the thread, that using existing keywords is best. That, or constructs like "scope (success)" where success isn't a keyword. I'm just currently a bit repelled by the pair "super const". -- Remove ".doesnotlike.spam" from the mail address.
Mar 16 2007
Deewiant wrote: [snip]In general, I do agree with your view, found elsewhere in the thread, that using existing keywords is best. That, or constructs like "scope (success)" where success isn't a keyword. I'm just currently a bit repelled by the pair "super const".Well how about "real const" then :oD. I think the good news is that you don't need to type it that often. You type: const char[] str = "Hi!"; and the compiler figures out the "super" part itself. Andrei
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Deewiant wrote: [snip]Doh! 'real const' of course... how could I leave that one out. 'real const' 'true const' 'double const' 'finally const' 'is const' or 'is finally super double true real const' --bbIn general, I do agree with your view, found elsewhere in the thread, that using existing keywords is best. That, or constructs like "scope (success)" where success isn't a keyword. I'm just currently a bit repelled by the pair "super const".Well how about "real const" then :oD. I think the good news is that you don't need to type it that often. You type: const char[] str = "Hi!"; and the compiler figures out the "super" part itself.
Mar 16 2007
Bill Baxter wrote:Andrei Alexandrescu (See Website For Email) wrote:'const is back and now its really mad' ?Deewiant wrote: [snip]Doh! 'real const' of course... how could I leave that one out. 'real const' 'true const' 'double const' 'finally const' 'is const' or 'is finally super double true real const'In general, I do agree with your view, found elsewhere in the thread, that using existing keywords is best. That, or constructs like "scope (success)" where success isn't a keyword. I'm just currently a bit repelled by the pair "super const".Well how about "real const" then :oD. I think the good news is that you don't need to type it that often. You type: const char[] str = "Hi!"; and the compiler figures out the "super" part itself.
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Working in NLP myself, I totally disagree. Natural language is rife with homonimy and synonimy, and we're all very, very happy with that. But in this case we don't even have to go that far: "super" is an adjective meaning primarily "of high grade or quality" and qualifies a noun. If there's no noun, you don't know what is "of high grade or quality". It's a fact, and we don't even blink. AndreiI've also worked in NLP quite a bit, but I don't think the constructs of natural languages are necessarily healthy in artificial languages. Many natural language constructs are only distinguishable through contextual analysis awareness or sense disambiguation (anaphora resolution and prepositional phrase attachment are among the most difficult to disambiguate). Natural languages rife with ambiguity may be easy for native speakers to disambiguate (thanks to the semantic model we develop during early childhood), but those ambiguities make it more difficult for adults to learn new languages. I like artificial languages to be artificial. I like them to be concise and unambiguous. I like them to have context-free grammars free from left-recursion. I don't like the word "static" to mean one thing in one context and something else entirely in another context. I don't like keywords to contain punctuation marks. And I don't like phrasal nouns (like "super const" or the inevitable "super duper const"). Just like highly ambiguous natural languages are difficult for adults to learn, I think synonymy and homonimy make it more difficult for professional developers to learn a new programming language. I used to write a lot of perl code, and the constructs it borrowed from natural language (synonymy, homonimy, anaphora, implied words, pronouns, etc) are some of the things that drove me away from the language toward But that's just me. Not everyone will agree with my opinion, and if I'm not in the consensus, I'll concede. But there seem to be a lot of people who agree with me. I reiterate: "const" and "readonly" are the way to go. (Methods which promise not to modify the values of their parameters should use "readonly" rather than "const" in their method signatures.) --benji
Mar 16 2007
Benji Smith wrote:Andrei Alexandrescu (See Website For Email) wrote:[snip] Me neither. Of course you don't want to do WSD to figure out the meaning of a keyword in a context. All I'm saying is that you can be expressive without blowing up your vocabulary by using collocations.Working in NLP myself, I totally disagree. Natural language is rife with homonimy and synonimy, and we're all very, very happy with that. But in this case we don't even have to go that far: "super" is an adjective meaning primarily "of high grade or quality" and qualifies a noun. If there's no noun, you don't know what is "of high grade or quality". It's a fact, and we don't even blink. AndreiI've also worked in NLP quite a bit, but I don't think the constructs of natural languages are necessarily healthy in artificial languages.I used to write a lot of perl code, and the constructs it borrowed from natural language (synonymy, homonimy, anaphora, implied words, pronouns, etc) are some of the things that drove me away from the language towardI think it's pretty clear to many in which places Perl went a little too far :o).But that's just me. Not everyone will agree with my opinion, and if I'm not in the consensus, I'll concede. But there seem to be a lot of people who agree with me.I don't think so. This discussion is very small in numbers, and the strength of the interlocutors' arguments does not increase their number. At the end of the day, if we design a good feature, people (who participated here or not) will be glad to use it; if not, they won't. And that's that.I reiterate: "const" and "readonly" are the way to go. (Methods which promise not to modify the values of their parameters should use "readonly" rather than "const" in their method signatures.)This makes const gratuitously incompatible to C++'s const, and (worse) also adds a keyword that's its equivalent. I don't think this can fly. Andrei
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:What???? Blasphemy!!!!But that's just me. Not everyone will agree with my opinion, and if I'm not in the consensus, I'll concede. But there seem to be a lot of people who agree with me.I don't think so. This discussion is very small in numbers, and the strength of the interlocutors' arguments does not increase their number.Good point. I like kris's suggestion to get rid of the "const" keyword entirely and replace it with something else ("constant" seems like a reasonable suggestion). Here are some other synonyms for "constant": http://thesaurus.reference.com/browse/constant There might be something useful in there. I'm personally fond of "chronic". :-) --benjiI reiterate: "const" and "readonly" are the way to go. (Methods which promise not to modify the values of their parameters should use "readonly" rather than "const" in their method signatures.)This makes const gratuitously incompatible to C++'s const, and (worse) also adds a keyword that's its equivalent. I don't think this can fly.
Mar 16 2007
Benji Smith wrote:Andrei Alexandrescu (See Website For Email) wrote:Believe me, I pored over thesauri for a long, long time. AndreiWhat???? Blasphemy!!!!But that's just me. Not everyone will agree with my opinion, and if I'm not in the consensus, I'll concede. But there seem to be a lot of people who agree with me.I don't think so. This discussion is very small in numbers, and the strength of the interlocutors' arguments does not increase their number.Good point. I like kris's suggestion to get rid of the "const" keyword entirely and replace it with something else ("constant" seems like a reasonable suggestion). Here are some other synonyms for "constant": http://thesaurus.reference.com/browse/constant There might be something useful in there. I'm personally fond of "chronic". :-)I reiterate: "const" and "readonly" are the way to go. (Methods which promise not to modify the values of their parameters should use "readonly" rather than "const" in their method signatures.)This makes const gratuitously incompatible to C++'s const, and (worse) also adds a keyword that's its equivalent. I don't think this can fly.
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:This makes const gratuitously incompatible to C++'s const, and (worse) also adds a keyword that's its equivalent. I don't think this can fly.There's some experience with that: the alias and typedef declarations. But that experience makes me wary of doing it in a much bigger way.
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Benji Smith wrote:What about 'immutable' for 'really can't change'/'superconst', and const can stay as is? --bbI reiterate: "const" and "readonly" are the way to go. (Methods which promise not to modify the values of their parameters should use "readonly" rather than "const" in their method signatures.)This makes const gratuitously incompatible to C++'s const, and (worse) also adds a keyword that's its equivalent. I don't think this can fly.
Mar 16 2007
Bill Baxter wrote:Andrei Alexandrescu (See Website For Email) wrote:I like it, and suggested it at a point. Walter said that it's bad marketing to define keywords in terms of a negative. AndreiBenji Smith wrote:What about 'immutable' for 'really can't change'/'superconst', and const can stay as is?I reiterate: "const" and "readonly" are the way to go. (Methods which promise not to modify the values of their parameters should use "readonly" rather than "const" in their method signatures.)This makes const gratuitously incompatible to C++'s const, and (worse) also adds a keyword that's its equivalent. I don't think this can fly.
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Bill Baxter wrote:So, "invariant" is already a keyword ... what about that? "Invariant" is currently used to stipulate a condition that must remain constant (or true) for the extent of the enclosing/relevant scope. Right now, it is used within a class only, but the semantics could presumably extend elsewhere too: invariant int * p = &x; void myFunc (invariant char[] arg) {} in both these cases, the "invariance" should remain for the extent of the relevant scope?Andrei Alexandrescu (See Website For Email) wrote:I like it, and suggested it at a point. Walter said that it's bad marketing to define keywords in terms of a negative.Benji Smith wrote:What about 'immutable' for 'really can't change'/'superconst', and const can stay as is?I reiterate: "const" and "readonly" are the way to go. (Methods which promise not to modify the values of their parameters should use "readonly" rather than "const" in their method signatures.)This makes const gratuitously incompatible to C++'s const, and (worse) also adds a keyword that's its equivalent. I don't think this can fly.
Mar 16 2007
kris wrote:Andrei Alexandrescu (See Website For Email) wrote:I completely missed that one. I think it's a good idea to look into it as a candidate for a qualifier name. Thank you. AndreiBill Baxter wrote:So, "invariant" is already a keyword ... what about that? "Invariant" is currently used to stipulate a condition that must remain constant (or true) for the extent of the enclosing/relevant scope. Right now, it is used within a class only, but the semantics could presumably extend elsewhere too: invariant int * p = &x; void myFunc (invariant char[] arg) {} in both these cases, the "invariance" should remain for the extent of the relevant scope?Andrei Alexandrescu (See Website For Email) wrote:I like it, and suggested it at a point. Walter said that it's bad marketing to define keywords in terms of a negative.Benji Smith wrote:What about 'immutable' for 'really can't change'/'superconst', and const can stay as is?I reiterate: "const" and "readonly" are the way to go. (Methods which promise not to modify the values of their parameters should use "readonly" rather than "const" in their method signatures.)This makes const gratuitously incompatible to C++'s const, and (worse) also adds a keyword that's its equivalent. I don't think this can fly.
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:kris wrote:[snip]yw If it gets tossed for whatever reason, It might be worthwhile renaming the current "invariant" to whatever is settled upon? That may reclaim a keyword at least.So, "invariant" is already a keyword ... what about that? "Invariant" is currently used to stipulate a condition that must remain constant (or true) for the extent of the enclosing/relevant scope. Right now, it is used within a class only, but the semantics could presumably extend elsewhere too: invariant int * p = &x; void myFunc (invariant char[] arg) {} in both these cases, the "invariance" should remain for the extent of the relevant scope?I completely missed that one. I think it's a good idea to look into it as a candidate for a qualifier name. Thank you.
Mar 16 2007
kris wrote:Andrei Alexandrescu (See Website For Email) wrote:Typically with invariants in CS the meaning is that "you can change all you want as long as you put things back the way you found them when you're done". And that's definitely not the connotation desired here.kris wrote:[snip]So, "invariant" is already a keyword ... what about that? "Invariant" is currently used to stipulate a condition that must remain constant (or true) for the extent of the enclosing/relevant scope. Right now, it is used within a class only, but the semantics could presumably extend elsewhere too: invariant int * p = &x; void myFunc (invariant char[] arg) {} in both these cases, the "invariance" should remain for the extent of the relevant scope?I completely missed that one. I think it's a good idea to look into it as a candidate for a qualifier name. Thank you.If it gets tossed for whatever reason, It might be worthwhile renaming the current "invariant" to whatever is settled upon? That may reclaim a keyword at least.Invariant can refer to an abstract property that doesn't change, like "full.length + empty.length == buffer.length". The individual constituents of that expression can change all they want. So calling it constant/readonly/immutable doesn't make as much sense as 'invariant'. --bb
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:kris wrote:I agree. I think: final const invariant for the three cases looks pretty good.So, "invariant" is already a keyword ... what about that?I completely missed that one. I think it's a good idea to look into it as a candidate for a qualifier name. Thank you.
Mar 17 2007
On Sat, 17 Mar 2007 19:09:16 -0700, Walter Bright wrote: I'm sorry I'm so thick, but have I got the idea right yet ... ?finalThis applies only to assignments to Write-Once RAM locations. This can be done by either the compiler or at run time depending on the amount of knowledge the compiler has about the location's usage.constThis is applied to declarations to prevent code in the same scope as the declaration from being able to modify the item being declared.invariantThis is applied to declarations to prevent code in the same application as the declaration from being able to modify the item being declared. As you can see, I'm confused as to how the qualifier effects which code is allowed to change which items. Even more so when it comes to reference items ... 'cos I'm not sure how to use these qualifiers to specify whether the reference and/or the data being referenced can be changed, and by whom. -- Derek Parnell Melbourne, Australia "Justice for David Hicks!" skype: derek.j.parnell
Mar 17 2007
Derek Parnell wrote:No. This applies to rebinding of a name: final x = 3; x = 4; // error, x is final i.e. final applies to the declared name, not the type.finalThis applies only to assignments to Write-Once RAM locations. This can be done by either the compiler or at run time depending on the amount of knowledge the compiler has about the location's usage.No. This means that it is a readonly view of data - other views of the same data may change it. char[] s = "hello".dup; const char[] t = s; t[0] = 'j'; // error, const char[] is a readonly view s[0] = 'j'; // ok writefln(t); // prints "jello" t = s[1..2]; // ok, as t is not final Note that const applies to the type, not the name.constThis is applied to declarations to prevent code in the same scope as the declaration from being able to modify the item being declared.Almost right. It isn't the declaration, but the *type* that is invariant. Invariant applies to the type, not the name.invariantThis is applied to declarations to prevent code in the same application as the declaration from being able to modify the item being declared.As you can see, I'm confused as to how the qualifier effects which code is allowed to change which items. Even more so when it comes to reference items ... 'cos I'm not sure how to use these qualifiers to specify whether the reference and/or the data being referenced can be changed, and by whom.'final' is a storage class, like 'static'. It doesn't apply to the type of the symbol, only the symbol itself. 'const' and 'invariant' apply to the type of the symbol, not the symbol.
Mar 17 2007
Walter Bright wrote:Derek Parnell wrote:[snip]By the way, "invariant" is a lifesaver. Everybody and their sister in the coffee shop liked it at the first sight. The girl at the counter asked for kris' email :o). Yes, "invariant" is essentially a synonym to "constant", but here are two simple mnemonic devices to remember which is which: a) "const" is shorter because it's used more often; b) "const" is similar to C++'s homonym. Easier to remember than perl's $|. AndreiAlmost right. It isn't the declaration, but the *type* that is invariant. Invariant applies to the type, not the name.invariantThis is applied to declarations to prevent code in the same application as the declaration from being able to modify the item being declared.
Mar 17 2007
Andrei Alexandrescu (See Website For Email) Wrote:Walter Bright wrote:Another option I'd like to have at least considered is the finding of a character that can be used to denote const. Adding various constnesses to all the code could easily add a whole lot of typing to the task of getting things done in D. Could we find a unicode character that wouldn't be too much trouble for editors to insert ? Might mean that D starts to require unicode source - but is that such a bad thing ? Are there any ascii characters that can be found that wont confuse the parser ? - like how the use of ! works for templates AlexDerek Parnell wrote:[snip]By the way, "invariant" is a lifesaver. Everybody and their sister in the coffee shop liked it at the first sight. The girl at the counter asked for kris' email :o). Yes, "invariant" is essentially a synonym to "constant", but here are two simple mnemonic devices to remember which is which: a) "const" is shorter because it's used more often; b) "const" is similar to C++'s homonym. Easier to remember than perl's $|. AndreiAlmost right. It isn't the declaration, but the *type* that is invariant. Invariant applies to the type, not the name.invariantThis is applied to declarations to prevent code in the same application as the declaration from being able to modify the item being declared.
Mar 18 2007
Alex Burton wrote:Andrei Alexandrescu (See Website For Email) Wrote:Type inference will reduce the need for littering code with "const" a great deal (when compared to today's C++ code, at least). You just write: auto var = expression; and the const will propagate. Initial experience will show whether this is enough. AndreiWalter Bright wrote:Another option I'd like to have at least considered is the finding of a character that can be used to denote const. Adding various constnesses to all the code could easily add a whole lot of typing to the task of getting things done in D. Could we find a unicode character that wouldn't be too much trouble for editors to insert ? Might mean that D starts to require unicode source - but is that such a bad thing ? Are there any ascii characters that can be found that wont confuse the parser ? - like how the use of ! works for templatesDerek Parnell wrote:[snip]By the way, "invariant" is a lifesaver. Everybody and their sister in the coffee shop liked it at the first sight. The girl at the counter asked for kris' email :o). Yes, "invariant" is essentially a synonym to "constant", but here are two simple mnemonic devices to remember which is which: a) "const" is shorter because it's used more often; b) "const" is similar to C++'s homonym. Easier to remember than perl's $|. AndreiAlmost right. It isn't the declaration, but the *type* that is invariant. Invariant applies to the type, not the name.invariantThis is applied to declarations to prevent code in the same application as the declaration from being able to modify the item being declared.
Mar 18 2007
Andrei Alexandrescu (See Website For Email) wrote:Alex Burton wrote:What about the ability to deduce only parts of a type? Declaring types is also a kind of documentation / assertion that can help maintainers of the code later. I might want to specify const and let the type be deduced, or I might want to specify the type I'm expecting and let const be deduced. Maybe declaration followed by is-test will be necessary for those cases. If they aren't too common I guess that's ok. But I would hate to see auto var = expression; assert(is(non_const_typeof(var)==Something)); become a standard idiom. ... how will one do that is() check for base type sans type constructors? --bbAndrei Alexandrescu (See Website For Email) Wrote:Type inference will reduce the need for littering code with "const" a great deal (when compared to today's C++ code, at least). You just write: auto var = expression; and the const will propagate. Initial experience will show whether this is enough.Walter Bright wrote:Another option I'd like to have at least considered is the finding of a character that can be used to denote const. Adding various constnesses to all the code could easily add a whole lot of typing to the task of getting things done in D. Could we find a unicode character that wouldn't be too much trouble for editors to insert ? Might mean that D starts to require unicode source - but is that such a bad thing ? Are there any ascii characters that can be found that wont confuse the parser ? - like how the use of ! works for templatesDerek Parnell wrote:[snip]By the way, "invariant" is a lifesaver. Everybody and their sister in the coffee shop liked it at the first sight. The girl at the counter asked for kris' email :o). Yes, "invariant" is essentially a synonym to "constant", but here are two simple mnemonic devices to remember which is which: a) "const" is shorter because it's used more often; b) "const" is similar to C++'s homonym. Easier to remember than perl's $|. AndreiAlmost right. It isn't the declaration, but the *type* that is invariant. Invariant applies to the type, not the name.invariantThis is applied to declarations to prevent code in the same application as the declaration from being able to modify the item being declared.
Mar 18 2007
Bill Baxter wrote:Andrei Alexandrescu (See Website For Email) wrote:assert(is(const typeof(var) == typeof(var))); Only time will show whether this will be needed frequently. I don't think so: in general var will engender an error upon first mutation, which is close to its definition. AndreiAlex Burton wrote:What about the ability to deduce only parts of a type? Declaring types is also a kind of documentation / assertion that can help maintainers of the code later. I might want to specify const and let the type be deduced, or I might want to specify the type I'm expecting and let const be deduced. Maybe declaration followed by is-test will be necessary for those cases. If they aren't too common I guess that's ok. But I would hate to see auto var = expression; assert(is(non_const_typeof(var)==Something)); become a standard idiom. ... how will one do that is() check for base type sans type constructors?Andrei Alexandrescu (See Website For Email) Wrote:Type inference will reduce the need for littering code with "const" a great deal (when compared to today's C++ code, at least). You just write: auto var = expression; and the const will propagate. Initial experience will show whether this is enough.Walter Bright wrote:Another option I'd like to have at least considered is the finding of a character that can be used to denote const. Adding various constnesses to all the code could easily add a whole lot of typing to the task of getting things done in D. Could we find a unicode character that wouldn't be too much trouble for editors to insert ? Might mean that D starts to require unicode source - but is that such a bad thing ? Are there any ascii characters that can be found that wont confuse the parser ? - like how the use of ! works for templatesDerek Parnell wrote:[snip]By the way, "invariant" is a lifesaver. Everybody and their sister in the coffee shop liked it at the first sight. The girl at the counter asked for kris' email :o). Yes, "invariant" is essentially a synonym to "constant", but here are two simple mnemonic devices to remember which is which: a) "const" is shorter because it's used more often; b) "const" is similar to C++'s homonym. Easier to remember than perl's $|. AndreiAlmost right. It isn't the declaration, but the *type* that is invariant. Invariant applies to the type, not the name.invariantThis is applied to declarations to prevent code in the same application as the declaration from being able to modify the item being declared.
Mar 18 2007
Andrei Alexandrescu (See Website For Email) wrote:Bill Baxter wrote:Why not just const auto var = expression; ? -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DAndrei Alexandrescu (See Website For Email) wrote:assert(is(const typeof(var) == typeof(var))); Only time will show whether this will be needed frequently. I don't think so: in general var will engender an error upon first mutation, which is close to its definition. AndreiAlex Burton wrote:What about the ability to deduce only parts of a type? Declaring types is also a kind of documentation / assertion that can help maintainers of the code later. I might want to specify const and let the type be deduced, or I might want to specify the type I'm expecting and let const be deduced. Maybe declaration followed by is-test will be necessary for those cases. If they aren't too common I guess that's ok. But I would hate to see auto var = expression; assert(is(non_const_typeof(var)==Something)); become a standard idiom. ... how will one do that is() check for base type sans type constructors?Andrei Alexandrescu (See Website For Email) Wrote:Type inference will reduce the need for littering code with "const" a great deal (when compared to today's C++ code, at least). You just write: auto var = expression; and the const will propagate. Initial experience will show whether this is enough.Walter Bright wrote:Another option I'd like to have at least considered is the finding of a character that can be used to denote const. Adding various constnesses to all the code could easily add a whole lot of typing to the task of getting things done in D. Could we find a unicode character that wouldn't be too much trouble for editors to insert ? Might mean that D starts to require unicode source - but is that such a bad thing ? Are there any ascii characters that can be found that wont confuse the parser ? - like how the use of ! works for templatesDerek Parnell wrote:[snip]By the way, "invariant" is a lifesaver. Everybody and their sister in the coffee shop liked it at the first sight. The girl at the counter asked for kris' email :o). Yes, "invariant" is essentially a synonym to "constant", but here are two simple mnemonic devices to remember which is which: a) "const" is shorter because it's used more often; b) "const" is similar to C++'s homonym. Easier to remember than perl's $|. AndreiAlmost right. It isn't the declaration, but the *type* that is invariant. Invariant applies to the type, not the name.invariantThis is applied to declarations to prevent code in the same application as the declaration from being able to modify the item being declared.
Mar 19 2007
On Sat, 17 Mar 2007 21:33:16 -0700, Walter Bright wrote:Derek Parnell wrote:I'm sure its just a terminology problem I'm having, but I still can't understand what you are trying to tell me. I'm sorry I'm so thick! To me the word 'type' refers to the data type associated with a symbol - like 'int', 'float', 'char[]' , etc... So when you say "'const' and 'invariant' apply to the type" it sounds like you are saying that 'const' prevents a symbol from changing types - which doesn't make sense to me. In D, a symbol can never change types once it has been declared. So, I'm now wondering if by "type" you are actually meaning the data represented by the symbol and not its data-type. However that doesn't quite make sense either because that's what I was saying but you disagreed with me!? Please bear with me. Oh, and anyone else can chime in to help make it clear to me too, please. Let's take 'final' again. Walter said:No. This applies to rebinding of a name: final x = 3; x = 4; // error, x is final i.e. final applies to the declared name, not the type.finalThis applies only to assignments to Write-Once RAM locations. This can be done by either the compiler or at run time depending on the amount of knowledge the compiler has about the location's usage.No. This means that it is a readonly view of data - other views of the same data may change it. char[] s = "hello".dup; const char[] t = s; t[0] = 'j'; // error, const char[] is a readonly view s[0] = 'j'; // ok writefln(t); // prints "jello" t = s[1..2]; // ok, as t is not final Note that const applies to the type, not the name.constThis is applied to declarations to prevent code in the same scope as the declaration from being able to modify the item being declared.Almost right. It isn't the declaration, but the *type* that is invariant. Invariant applies to the type, not the name.invariantThis is applied to declarations to prevent code in the same application as the declaration from being able to modify the item being declared.As you can see, I'm confused as to how the qualifier effects which code is allowed to change which items. Even more so when it comes to reference items ... 'cos I'm not sure how to use these qualifiers to specify whether the reference and/or the data being referenced can be changed, and by whom.'final' is a storage class, like 'static'. It doesn't apply to the type of the symbol, only the symbol itself. 'const' and 'invariant' apply to the type of the symbol, not the symbol.No. This applies to rebinding of a name: final x = 3; x = 4; // error, x is final i.e. final applies to the declared name, not the type.Now by 'binding' I assume you mean 'having the compiler associate a value with a symbol'. So "final x = 3" is sort of equivalent to C's "#define x (3)", but in D there are scope and data-type implications. I expect that in D we will also be able to do ... final double z = 4.288392; but what about things like ... int y = 3; final x = y; final q = someFunc(); And is ... final s = "qwerty"; char[] t = s; identical to ... char[] t = "qwerty".dup; I presume this would fail at compile time ... void XYZZY(inout char[] x) { . . . } . . . final s = "qwerty"; XYZZY(s); ***** Okay, now let's revisit 'const'. I said ...And you said ...This is applied to declarations to prevent code in the same scope as the declaration from being able to modify the item being declared.No. This means that it is a readonly view of data - other views of the same data may change it. char[] s = "hello".dup; const char[] t = s; t[0] = 'j'; // error, const char[] is a readonly view s[0] = 'j'; // ok writefln(t); // prints "jello" t = s[1..2]; // ok, as t is not final Note that const applies to the type, not the name.Apart from the last sentence, which still confuses the hell out of me, I think we almost are saying the same thing. Using your example code, I was saying that the declaration "const char[] t" means that you can't change 't' (i.e. t.ptr and t.length cannot be altered) but you can change the data that t.ptr points to. However, I see by your explanation that I got this the wrong way around. I now read you saying that 'const char[] t' means that program can change t.ptr and/or t.length but it cannot use 't' to change the data it points to. I said nothing about getting to the data via another symbol. Also, I see that you are saying "final const char[] t" means that neither 't' nor its data can be altered. Is there any difference between "final const char[] t" and "const final char[] t"? Is "const int x = 4" and "final int x = 4" mean the same thing (not a reference type this time)? Would "final const x = 5" compile? Would it mean anything different from just 'final' or just 'const'? It would seem that 'const' is primarily used to protect referenced data rather than the reference itself. Is that right? Will this be allowed ... void XYZZY(const char[] s) { char[] t; t = s; // fails here? t[0] = 'a'; } ***** And now to 'invariant' ... You said ...It isn't the declaration, but the *type* that is invariant. Invariant applies to the type, not the name.I have no idea what you mean by that statement! I still can't see that data-types can change. But maybe you mean data rather than data-type, but then isn't that what 'const' is doing? And I'm sure you *do not* mean that somehow you can rename symbols during compilation!? So I can't see what is "invariant" - as in - what is "not changing". If I code "invariant char[] t", ... (A) are changes to t.ptr/t.length prevented? (B) are changes to the data that 't' points to prevented? How is 'invariant' different from 'final'? How is 'invariant' different from 'const'? How is 'invariant' different from 'final const'? Is combining 'invariant' with 'final' and/or 'const' meaningful? If so, how? -- Derek (skype: derek.j.parnell) Melbourne, Australia "Justice for David Hicks!" 19/03/2007 11:55:33 AM
Mar 18 2007
Derek Parnell wrote:On Sat, 17 Mar 2007 21:33:16 -0700, Walter Bright wrote:It's just saying that "T" and "const T" are different types (unless T was already const); they have different permitted operations. I'd have to say that I find Walter's ideas on const/final to be rather... distinctive... and we've debated terminology at some length but with no resolution. It's his language, he can use terms as he wishes. It may impede communication. This may be a case of "final" being a thing that Walter likes to think of as a storage class rather than a type modifier (though in a more general sense storage classes are just a special/restricted case of type modifiers). "final", I think, is a workaround for handling types that are accessed through automatically-dereferenced GC'd pointers in D. The auto-deref property hides the actual type of those pointers from us, so we can't const- qualify them; we just end up adding const to the type to which they point. C++ doesn't work this way, and so const does everything that final does and more in C++. It's just different. If you want indirection via a reference/pointer, C++ makes you say so, but gives you the chance to apply type modifiers to that pointer. D does it invisibly, but then requires extra syntax to be able to stop the name being rebindable. -- JamesDerek Parnell wrote:I'm sure its just a terminology problem I'm having, but I still can't understand what you are trying to tell me. I'm sorry I'm so thick! To me the word 'type' refers to the data type associated with a symbol - like 'int', 'float', 'char[]' , etc... So when you say "'const' and 'invariant' apply to the type" it sounds like you are saying that 'const' prevents a symbol from changing types - which doesn't make sense to me. In D, a symbol can never change types once it has been declared.No. This applies to rebinding of a name: final x = 3; x = 4; // error, x is final i.e. final applies to the declared name, not the type.finalThis applies only to assignments to Write-Once RAM locations. This can be done by either the compiler or at run time depending on the amount of knowledge the compiler has about the location's usage.No. This means that it is a readonly view of data - other views of the same data may change it. char[] s = "hello".dup; const char[] t = s; t[0] = 'j'; // error, const char[] is a readonly view s[0] = 'j'; // ok writefln(t); // prints "jello" t = s[1..2]; // ok, as t is not final Note that const applies to the type, not the name.constThis is applied to declarations to prevent code in the same scope as the declaration from being able to modify the item being declared.Almost right. It isn't the declaration, but the *type* that is invariant. Invariant applies to the type, not the name.invariantThis is applied to declarations to prevent code in the same application as the declaration from being able to modify the item being declared.As you can see, I'm confused as to how the qualifier effects which code is allowed to change which items. Even more so when it comes to reference items ... 'cos I'm not sure how to use these qualifiers to specify whether the reference and/or the data being referenced can be changed, and by whom.'final' is a storage class, like 'static'. It doesn't apply to the type of the symbol, only the symbol itself. 'const' and 'invariant' apply to the type of the symbol, not the symbol.
Mar 18 2007
On Sun, 18 Mar 2007 20:46:58 -0700, James Dennett wrote: Walter says"'const' and 'invariant' apply to the type"It's just saying that "T" and "const T" are different types (unless T was already const); they have different permitted operations.Oh?! Is that all. That is easy to understand, but it does not help me understand how Walter sees it or 'invariant' being used. So "int", "const int" and "invariant int" are all different types and as such have in-built rules concerning implicit conversions etc...That's fine. I can understand that. But what then are the built-rules? Are the rules different for POD, Objects, and Arrays?I'd have to say that I find Walter's ideas on const/final to be rather... distinctive... and we've debated terminology at some length but with no resolution. It's his language, he can use terms as he wishes. It may impede communication.I'm fine with that too. Sure, its Walter (and Andrei's) language and that can make up syntax and keywords as they see fit. I only hope that they get some good documentation experts to help people like me understand it.This may be a case of "final" being a thing that Walter likes to think of as a storage class rather than a type modifier (though in a more general sense storage classes are just a special/restricted case of type modifiers). "final", I think, is a workaround for handling types that are accessed through automatically-dereferenced GC'd pointers in D. The auto-deref property hides the actual type of those pointers from us, so we can't const- qualify them; we just end up adding const to the type to which they point. C++ doesn't work this way, and so const does everything that final does and more in C++. It's just different. If you want indirection via a reference/pointer, C++ makes you say so, but gives you the chance to apply type modifiers to that pointer. D does it invisibly, but then requires extra syntax to be able to stop the name being rebindable.Interesting ... but what does all that sound like in English <G> I don't really know C++ all that well so I don't quite get the comparisons. Can anyone explain this without referring to other programming languages, please? Just common everyday English would be nice - oh, but with example <G>. But let's see if I can translate it first ... "storage class" means how something's value is stored in RAM. Which could be in the data space or as immediate literals in the code space. Thus 'final' is a description of how the compiler sees the value stored in the program. One rule is that it is impossible for any code to alter the value associated (bound) a 'final' symbol. For all practical purposes, from the compiler's point of view, the symbol *is* the value. When applied to reference types, the symbol's value is the reference and not that which is being referenced. -- Derek (skype: derek.j.parnell) Melbourne, Australia "Justice for David Hicks!" 19/03/2007 3:24:59 PM
Mar 18 2007
James Dennett Wrote:"final", I think, is a workaround for handling types that are accessed through automatically-dereferenced GC'd pointers in D. The auto-deref property hides the actual type of those pointers from us, so we can't const- qualify them; we just end up adding const to the type to which they point. C++ doesn't work this way, and so const does everything that final does and more in C++. It's just different. If you want indirection via a reference/pointer, C++ makes you say so, but gives you the chance to apply type modifiers to that pointer. D does it invisibly, but then requires extra syntax to be able to stop the name being rebindable.But I think it is'nt key point here. As I understand, const will afect all from the specified stage in the reference chain, unlike C++ const? Code analogous to this legal C++ code will be compile time error? struct S { int *x; }; int a = 12; S s = { &a }; const S *p = &s; *p->x = 20; // will be error? jovo
Mar 19 2007
jovo wrote:James Dennett Wrote:Yes. D's const is transitive. Andrei"final", I think, is a workaround for handling types that are accessed through automatically-dereferenced GC'd pointers in D. The auto-deref property hides the actual type of those pointers from us, so we can't const- qualify them; we just end up adding const to the type to which they point. C++ doesn't work this way, and so const does everything that final does and more in C++. It's just different. If you want indirection via a reference/pointer, C++ makes you say so, but gives you the chance to apply type modifiers to that pointer. D does it invisibly, but then requires extra syntax to be able to stop the name being rebindable.But I think it is'nt key point here. As I understand, const will afect all from the specified stage in the reference chain, unlike C++ const? Code analogous to this legal C++ code will be compile time error? struct S { int *x; }; int a = 12; S s = { &a }; const S *p = &s; *p->x = 20; // will be error?
Mar 19 2007
Andrei Alexandrescu (See Website For Email) Wrote:Yes. D's const is transitive.So: finall = stage0_nontransitive_const? const = stage1_transitive_const? May be beter to separete concepts? Do we need stage1_const? Do we need nontransitive_const? jovo
Mar 19 2007
jovo wrote:Andrei Alexandrescu (See Website For Email) Wrote:If I understand the above properly, yes.Yes. D's const is transitive.So: finall = stage0_nontransitive_const? const = stage1_transitive_const?May be beter to separete concepts? Do we need stage1_const? Do we need nontransitive_const?So rarely that we decided they can be ruled out. They'd complicate the type system gravely, for very little benefit. Andrei
Mar 19 2007
Derek Parnell wrote:On Sat, 17 Mar 2007 21:33:16 -0700, Walter Bright wrote:It's likely the following: By "It doesn't apply to the type of the symbol, only the symbol itself." it means it applies to the immediate-value, and by "apply to the type of the symbol, not the symbol" it means it applies to the referenced-data, where: "immediate-value" means the value that is changed on assignments, which in primitives is the primitive value, and on references is the pointer (memory location). "referenced-data" is the data obtained through references (i.e., data pointed to) IMO I think that terminology is faulty, since, for starters, one can have an expression that is not assignable (like the return value of functions), which is the same as being 'final', yet there is no associated symbol. The same applies to saying 'final' "applies to rebinding of a name", like in the example below:Derek Parnell wrote:I'm sure its just a terminology problem I'm having, but I still can't understand what you are trying to tell me. I'm sorry I'm so thick!No. This applies to rebinding of a name: final x = 3; x = 4; // error, x is final i.e. final applies to the declared name, not the type.finalThis applies only to assignments to Write-Once RAM locations. This can be done by either the compiler or at run time depending on the amount of knowledge the compiler has about the location's usage.No. This means that it is a readonly view of data - other views of the same data may change it. char[] s = "hello".dup; const char[] t = s; t[0] = 'j'; // error, const char[] is a readonly view s[0] = 'j'; // ok writefln(t); // prints "jello" t = s[1..2]; // ok, as t is not final Note that const applies to the type, not the name.constThis is applied to declarations to prevent code in the same scope as the declaration from being able to modify the item being declared.Almost right. It isn't the declaration, but the *type* that is invariant. Invariant applies to the type, not the name.invariantThis is applied to declarations to prevent code in the same application as the declaration from being able to modify the item being declared.As you can see, I'm confused as to how the qualifier effects which code is allowed to change which items. Even more so when it comes to reference items ... 'cos I'm not sure how to use these qualifiers to specify whether the reference and/or the data being referenced can be changed, and by whom.'final' is a storage class, like 'static'. It doesn't apply to the type of the symbol, only the symbol itself. 'const' and 'invariant' apply to the type of the symbol, not the symbol.Walter said:The differences are that the 'final' variable exists at runtime (unlike #define) and as such the initializer doesn't have to be a constant, and the var can be referenced.No. This applies to rebinding of a name: final x = 3; x = 4; // error, x is final i.e. final applies to the declared name, not the type.Now by 'binding' I assume you mean 'having the compiler associate a value with a symbol'. So "final x = 3" is sort of equivalent to C's "#define x (3)", but in D there are scope and data-type implications.I expect that in D we will also be able to do ... final double z = 4.288392; but what about things like ... int y = 3; final x = y; final q = someFunc();Yes.And is ... final s = "qwerty"; char[] t = s; identical to ... char[] t = "qwerty".dup;No, I don't think so, why would it be?I presume this would fail at compile time ... void XYZZY(inout char[] x) { . . . } . . . final s = "qwerty"; XYZZY(s);Yup.***** Okay, now let's revisit 'const'. I said ...That's what 'final' does (i.e. "t.ptr and t.length cannot be altered").And you said ...This is applied to declarations to prevent code in the same scope as the declaration from being able to modify the item being declared.No. This means that it is a readonly view of data - other views of the same data may change it. char[] s = "hello".dup; const char[] t = s; t[0] = 'j'; // error, const char[] is a readonly view s[0] = 'j'; // ok writefln(t); // prints "jello" t = s[1..2]; // ok, as t is not final Note that const applies to the type, not the name.Apart from the last sentence, which still confuses the hell out of me, I think we almost are saying the same thing. Using your example code, I was saying that the declaration "const char[] t" means that you can't change 't' (i.e. t.ptr and t.length cannot be altered) but you can change the data that t.ptr points to.However, I see by your explanation that I got this the wrong way around. I now read you saying that 'const char[] t' means that program can change t.ptr and/or t.length but it cannot use 't' to change the data it points to. I said nothing about getting to the data via another symbol. Also, I see that you are saying "final const char[] t" means that neither 't' nor its data can be altered. Is there any difference between "final const char[] t" and "const final char[] t"?Nope.Is "const int x = 4" and "final int x = 4" mean the same thing (not a reference type this time)?I suspect no, since 'const' for primitives is either ignored or not allowed, but I'm not sure what Andrei is planning it to be.Would "final const x = 5" compile? Would it mean anything different from just 'final' or just 'const'?Same as above, dunno.It would seem that 'const' is primarily used to protect referenced data rather than the reference itself. Is that right?Yup.And now to 'invariant' ...For what I got 'invariant' means the data doesn't change at all, like compile time constants, or ROM data. But I didn't understand if it applies to the "immediate-value" only (like 'final'), or transitively to the referenced data too (like 'const'). Clarify? -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Mar 19 2007
Bruno Medeiros wrote:For what I got 'invariant' means the data doesn't change at all, like compile time constants, or ROM data. But I didn't understand if it applies to the "immediate-value" only (like 'final'), or transitively to the referenced data too (like 'const'). Clarify?Its my understanding that 'invariant' becomes part of the type, like 'const'. So in your terms, it applies to "referenced data". invariant ANSWER = 42 ; bool question (invariant int guess) { return guess is ANSWER; } ;) -- Chris Nicholson-Sauls
Mar 19 2007
Bruno has answered your specific questions, so I'll take a more general tack. A symbol is a name to which is 'bound' a value. static int x = 3; '3' is the value. 'int' is the type. 'x' is the symbol. 'static' is the storage class. Here, we bind a new value to the symbol x: x = 4; A storage class originally meant where the symbol is stored, such as in the data segment, on the stack, in a register, or in ROM. It's been generalized a bit since then. The main way to tell a storage class apart is that: 1) a storage class applies to the symbol 2) a type is independent of storage class, i.e. you cannot create a type that is "pointer to static" or "array of extern". Storage classes do not affect overloading, nor type deduction. 'invariant' and 'const' are type modifiers (aka type constructors), which mean when they are applied to a type, a new type is created that is a combination. 'invariant' is a guarantee that any data of that type will never change. 'const' is a guarantee that any data of that type will never be modified through a reference to that type (though other, non-const references to that type can modify the data).
Mar 20 2007
On Tue, 20 Mar 2007 16:01:35 -0700, Walter Bright wrote:A symbol is a name to which is 'bound' a value....Here, we bind a new value to the symbol x: x = 4;I used to use the verb 'to assign' for this concept. I guess that's still okay or must I modernize <G>static int x = 3; '3' is the value. 'int' is the type. 'x' is the symbol. 'static' is the storage class. A storage class originally meant where the symbol is stored, such as in the data segment, on the stack, in a register, or in ROM. It's been generalized a bit since then. The main way to tell a storage class apart is that: 1) a storage class applies to the symbol"to the symbol"? Don't you mean "to the data that the symbol represents"? In the case above, the symbol is 'x', and I don't think 'x' is being stored anywhere except in the compiler's internal tables, and I'm sure 'static' isn't referring to the compiler's internals.'invariant' is a guarantee that any data of that type will never change.class Foo { int a; char[] s; this(char[] d) { s = d.dup; a = s.length; } } invariant Foo f = new Foo("nice"); f.a = 1; // fails??? changing f's data f.s = "bad"; // fails??? changing f's data f.s.length = 1; // fails??? changing f's data f.s[0] = 'r'; // okay ??? not changing f's data f = new Foo("rabbit"); // okay 'cos 'f' is a reference // and not the object???'const' is a guarantee that any data of that type will never be modified through a reference to that type (though other, non-const references to that type can modify the data).const Foo f = new Foo("nice"); Foo g = f; f.a = 1; // fails??? changing f's data g.a = 1; // okay??? Using 'g' and not 'f'. f.s = "bad"; // fails??? changing f's data g.s = "bad"; // okay??? Using 'g' and not 'f'. f.s.length = 1; // fails??? changing f's data g.s.length = 1; // okay??? Using 'g' and not 'f'. f.s[0] = 'r'; // okay ??? not changing f's data f = new Foo("rabbit"); // okay 'cos 'f' is a reference // and not the object??? (*(&f)).a = 1; // okay??? access through f's address and not 'f'. -- Derek (skype: derek.j.parnell) Melbourne, Australia "Justice for David Hicks!" 21/03/2007 10:39:07 AM
Mar 20 2007
Derek Parnell wrote:On Tue, 20 Mar 2007 16:01:35 -0700, Walter Bright wrote:You may want to modernize. "Assign" doesn't quite catch the notion of indirect reference, and from a couple of posts I understand that this is a source of confusion. A very useful way to see "int x = 4;" is that the symbol x is bound to the Platonic number 4. The 4 itself cannot change. You can rebind x by, say, writing ++x. That unbinds x from Plato 4 and binds it to Plato 5. Once this is clear, the notions of values and references clarifies a lot.A symbol is a name to which is 'bound' a value....Here, we bind a new value to the symbol x: x = 4;I used to use the verb 'to assign' for this concept. I guess that's still okay or must I modernize <G>The meaning was simple. When you say "poor fella Jim", "poor" applies to Jim, not to "fella".static int x = 3; '3' is the value. 'int' is the type. 'x' is the symbol. 'static' is the storage class. A storage class originally meant where the symbol is stored, such as in the data segment, on the stack, in a register, or in ROM. It's been generalized a bit since then. The main way to tell a storage class apart is that: 1) a storage class applies to the symbol"to the symbol"? Don't you mean "to the data that the symbol represents"? In the case above, the symbol is 'x', and I don't think 'x' is being stored anywhere except in the compiler's internal tables, and I'm sure 'static' isn't referring to the compiler's internals.They all fail. The last fails because invariance is transitive. All that could be done is to rebind f to another invariant object. Andrei'invariant' is a guarantee that any data of that type will never change.class Foo { int a; char[] s; this(char[] d) { s = d.dup; a = s.length; } } invariant Foo f = new Foo("nice"); f.a = 1; // fails??? changing f's data f.s = "bad"; // fails??? changing f's data f.s.length = 1; // fails??? changing f's data f.s[0] = 'r'; // okay ??? not changing f's data
Mar 20 2007
On Tue, 20 Mar 2007 17:24:49 -0700, Andrei Alexandrescu (See Website For Email) wrote:Derek Parnell wrote:Okay, if you say so, but I'm not having an issue with the concept of assigning value to something directly or indirectly.On Tue, 20 Mar 2007 16:01:35 -0700, Walter Bright wrote:You may want to modernize. "Assign" doesn't quite catch the notion of indirect reference,A symbol is a name to which is 'bound' a value....Here, we bind a new value to the symbol x: x = 4;I used to use the verb 'to assign' for this concept. I guess that's still okay or must I modernize <G>and from a couple of posts I understand that this is a source of confusion.Not for me, but thanks anyway.A very useful way to see "int x = 4;" is that the symbol x is bound to the Platonic number 4. The 4 itself cannot change. You can rebind x by, say, writing ++x. That unbinds x from Plato 4 and binds it to Plato 5.Huh? Just looks like a fancy way of saying 'x' first gets assigned the value 4 then later, using ++x, gets assigned the value 5. By whatever, I'll not get hung up as I think we are on the same track here.Once this is clear, the notions of values and references clarifies a lot.It does? How? If pressed, I'd say that the only difference between 'assign' and 'bind' is that 'assign' maybe implies an 'assignment statement' was used to change the value, but 'bind' doesn't care how the change is caused.Oh, okay ... its not a 'static int' (a type) but a 'static x' (a value represented by the symbol 'x').The meaning was simple. When you say "poor fella Jim", "poor" applies to Jim, not to "fella".static int x = 3; '3' is the value. 'int' is the type. 'x' is the symbol. 'static' is the storage class. A storage class originally meant where the symbol is stored, such as in the data segment, on the stack, in a register, or in ROM. It's been generalized a bit since then. The main way to tell a storage class apart is that: 1) a storage class applies to the symbol"to the symbol"? Don't you mean "to the data that the symbol represents"? In the case above, the symbol is 'x', and I don't think 'x' is being stored anywhere except in the compiler's internal tables, and I'm sure 'static' isn't referring to the compiler's internals.Thanks. I'm just trying to get all this straight in my mind. So the definition should be more along the lines of ... 'invariant' is a guarantee that any data accessible from that type will never change. -- Derek (skype: derek.j.parnell) Melbourne, Australia "Justice for David Hicks!" 21/03/2007 11:52:49 AMThey all fail. The last fails because invariance is transitive. All that could be done is to rebind f to another invariant object.'invariant' is a guarantee that any data of that type will never change.class Foo { int a; char[] s; this(char[] d) { s = d.dup; a = s.length; } } invariant Foo f = new Foo("nice"); f.a = 1; // fails??? changing f's data f.s = "bad"; // fails??? changing f's data f.s.length = 1; // fails??? changing f's data f.s[0] = 'r'; // okay ??? not changing f's data
Mar 20 2007
Derek Parnell wrote:On Tue, 20 Mar 2007 17:24:49 -0700, Andrei Alexandrescu (See Website For Email) wrote:No. The difference is major. The binding to Platonic values clarifies that values are exactly the same thing as references to immutable objects. Once that is understood, it's very easy to understand all of D's immutability minutiae. AndreiDerek Parnell wrote:Okay, if you say so, but I'm not having an issue with the concept of assigning value to something directly or indirectly.On Tue, 20 Mar 2007 16:01:35 -0700, Walter Bright wrote:You may want to modernize. "Assign" doesn't quite catch the notion of indirect reference,A symbol is a name to which is 'bound' a value....Here, we bind a new value to the symbol x: x = 4;I used to use the verb 'to assign' for this concept. I guess that's still okay or must I modernize <G>and from a couple of posts I understand that this is a source of confusion.Not for me, but thanks anyway.A very useful way to see "int x = 4;" is that the symbol x is bound to the Platonic number 4. The 4 itself cannot change. You can rebind x by, say, writing ++x. That unbinds x from Plato 4 and binds it to Plato 5.Huh? Just looks like a fancy way of saying 'x' first gets assigned the value 4 then later, using ++x, gets assigned the value 5. By whatever, I'll not get hung up as I think we are on the same track here.Once this is clear, the notions of values and references clarifies a lot.It does? How? If pressed, I'd say that the only difference between 'assign' and 'bind' is that 'assign' maybe implies an 'assignment statement' was used to change the value, but 'bind' doesn't care how the change is caused.
Mar 20 2007
Andrei Alexandrescu (See Website For Email) Wrote:You may want to modernize. "Assign" doesn't quite catch the notion of indirect reference, and from a couple of posts I understand that this is a source of confusion. A very useful way to see "int x = 4;" is that the symbol x is bound to the Platonic number 4. The 4 itself cannot change. You can rebind x by, say, writing ++x. That unbinds x from Plato 4 and binds it to Plato 5. Once this is clear, the notions of values and references clarifies a lot.Actually, when I use this term: struct S { int a; int* b; } const S s; s.a = 1; // not allowed s.b = some_address; // not allowed *s.b = 1; // not allowed s = some_S; // allowed don't look alogical, and what is more important, produces, I think at first look, better result. jovo
Mar 20 2007
Andrei Alexandrescu (See Website For Email) wrote:Derek Parnell wrote:Huh, " "Assign" doesn't quite catch the notion of indirect reference", what do you mean by that? I too was thinking that "assign" is a much better term than "binding".On Tue, 20 Mar 2007 16:01:35 -0700, Walter Bright wrote:You may want to modernize. "Assign" doesn't quite catch the notion of indirect reference, and from a couple of posts I understand that this is a source of confusion.A symbol is a name to which is 'bound' a value....Here, we bind a new value to the symbol x: x = 4;I used to use the verb 'to assign' for this concept. I guess that's still okay or must I modernize <G>A very useful way to see "int x = 4;" is that the symbol x is bound to the Platonic number 4. The 4 itself cannot change. You can rebind x by, say, writing ++x. That unbinds x from Plato 4 and binds it to Plato 5. Once this is clear, the notions of values and references clarifies a lot.Dear Gods. Yes, that conceptualization is correct, but again, how is it any better than "assign"/"assignability"? A very useful way to see "int x = 4;" is that the symbol x is assigned to the value 4. You can reassign x by writing ++x. That assigns x to the value x+1. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Mar 23 2007
Bruno Medeiros wrote:Andrei Alexandrescu (See Website For Email) wrote:That is what really happens, but won't help understanding references. So it is not useful for that purpose. AndreiDerek Parnell wrote:Huh, " "Assign" doesn't quite catch the notion of indirect reference", what do you mean by that? I too was thinking that "assign" is a much better term than "binding".On Tue, 20 Mar 2007 16:01:35 -0700, Walter Bright wrote:You may want to modernize. "Assign" doesn't quite catch the notion of indirect reference, and from a couple of posts I understand that this is a source of confusion.A symbol is a name to which is 'bound' a value....Here, we bind a new value to the symbol x: x = 4;I used to use the verb 'to assign' for this concept. I guess that's still okay or must I modernize <G>A very useful way to see "int x = 4;" is that the symbol x is bound to the Platonic number 4. The 4 itself cannot change. You can rebind x by, say, writing ++x. That unbinds x from Plato 4 and binds it to Plato 5. Once this is clear, the notions of values and references clarifies a lot.Dear Gods. Yes, that conceptualization is correct, but again, how is it any better than "assign"/"assignability"? A very useful way to see "int x = 4;" is that the symbol x is assigned to the value 4. You can reassign x by writing ++x. That assigns x to the value x+1.
Mar 23 2007
Andrei Alexandrescu (See Website For Email) wrote:Bruno Medeiros wrote:Yes, that you've said already, what I would like to know is why. :P What's the issue with assign and references? -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DAndrei Alexandrescu (See Website For Email) wrote:That is what really happens, but won't help understanding references. So it is not useful for that purpose. AndreiDerek Parnell wrote:Huh, " "Assign" doesn't quite catch the notion of indirect reference", what do you mean by that? I too was thinking that "assign" is a much better term than "binding".On Tue, 20 Mar 2007 16:01:35 -0700, Walter Bright wrote:You may want to modernize. "Assign" doesn't quite catch the notion of indirect reference, and from a couple of posts I understand that this is a source of confusion.A symbol is a name to which is 'bound' a value....Here, we bind a new value to the symbol x: x = 4;I used to use the verb 'to assign' for this concept. I guess that's still okay or must I modernize <G>A very useful way to see "int x = 4;" is that the symbol x is bound to the Platonic number 4. The 4 itself cannot change. You can rebind x by, say, writing ++x. That unbinds x from Plato 4 and binds it to Plato 5. Once this is clear, the notions of values and references clarifies a lot.Dear Gods. Yes, that conceptualization is correct, but again, how is it any better than "assign"/"assignability"? A very useful way to see "int x = 4;" is that the symbol x is assigned to the value 4. You can reassign x by writing ++x. That assigns x to the value x+1.
Mar 23 2007
Derek Parnell wrote:Since the above case wasn't answered, I will. The "Foo g = f;" statement isn't allowed at all, because you are casting a const (think readonly) reference to a non-const reference. That isn't allowed, by design, since the very purpose of const (think readonly), is to disallow the holder of that reference to do any changes on the reference data. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D'const' is a guarantee that any data of that type will never be modified through a reference to that type (though other, non-const references to that type can modify the data).const Foo f = new Foo("nice"); Foo g = f;
Mar 23 2007
Walter Bright wrote:Bruno has answered your specific questions, so I'll take a more general tack. A symbol is a name to which is 'bound' a value. static int x = 3; '3' is the value. 'int' is the type. 'x' is the symbol. 'static' is the storage class. Here, we bind a new value to the symbol x: x = 4; A storage class originally meant where the symbol is stored, such as in the data segment, on the stack, in a register, or in ROM. It's been generalized a bit since then. The main way to tell a storage class apart is that: 1) a storage class applies to the symbol 2) a type is independent of storage class, i.e. you cannot create a type that is "pointer to static" or "array of extern". Storage classes do not affect overloading, nor type deduction. 'invariant' and 'const' are type modifiers (aka type constructors), which mean when they are applied to a type, a new type is created that is a combination. 'invariant' is a guarantee that any data of that type will never change. 'const' is a guarantee that any data of that type will never be modified through a reference to that type (though other, non-const references to that type can modify the data).So 'final' will be a storage class and not a type modifier? That's one of the questions I still have with regards to your design, because I'm not seeing how 'final' can also not-be a type modifier. In particular, again, what is typeof(&foo) where foo is: final Foo foo; ? -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Mar 23 2007
Bruno Medeiros wrote:Walter Bright wrote:I imagine it would be (invariant Foo*): an invariant pointer to a reference to a Foo. Since *no one* is ever allowed to change final storage, then a pointer to it must be invariant. -- Daniel -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/Bruno has answered your specific questions, so I'll take a more general tack. A symbol is a name to which is 'bound' a value. static int x = 3; '3' is the value. 'int' is the type. 'x' is the symbol. 'static' is the storage class. Here, we bind a new value to the symbol x: x = 4; A storage class originally meant where the symbol is stored, such as in the data segment, on the stack, in a register, or in ROM. It's been generalized a bit since then. The main way to tell a storage class apart is that: 1) a storage class applies to the symbol 2) a type is independent of storage class, i.e. you cannot create a type that is "pointer to static" or "array of extern". Storage classes do not affect overloading, nor type deduction. 'invariant' and 'const' are type modifiers (aka type constructors), which mean when they are applied to a type, a new type is created that is a combination. 'invariant' is a guarantee that any data of that type will never change. 'const' is a guarantee that any data of that type will never be modified through a reference to that type (though other, non-const references to that type can modify the data).So 'final' will be a storage class and not a type modifier? That's one of the questions I still have with regards to your design, because I'm not seeing how 'final' can also not-be a type modifier. In particular, again, what is typeof(&foo) where foo is: final Foo foo; ?
Mar 23 2007
Daniel Keep wrote:Bruno Medeiros wrote:No, that's not possible. It was mentioned before in another post: news://news.digitalmars.com:119/etv81l$m94$1 digitalmars.com Since invariant is (planned to be) transitive, then that typeof can't be (invariant Foo*), since the contents of foo can change (altough the immediate-value won't). -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DWalter Bright wrote:I imagine it would be (invariant Foo*): an invariant pointer to a reference to a Foo. Since *no one* is ever allowed to change final storage, then a pointer to it must be invariant. -- DanielBruno has answered your specific questions, so I'll take a more general tack. A symbol is a name to which is 'bound' a value. static int x = 3; '3' is the value. 'int' is the type. 'x' is the symbol. 'static' is the storage class. Here, we bind a new value to the symbol x: x = 4; A storage class originally meant where the symbol is stored, such as in the data segment, on the stack, in a register, or in ROM. It's been generalized a bit since then. The main way to tell a storage class apart is that: 1) a storage class applies to the symbol 2) a type is independent of storage class, i.e. you cannot create a type that is "pointer to static" or "array of extern". Storage classes do not affect overloading, nor type deduction. 'invariant' and 'const' are type modifiers (aka type constructors), which mean when they are applied to a type, a new type is created that is a combination. 'invariant' is a guarantee that any data of that type will never change. 'const' is a guarantee that any data of that type will never be modified through a reference to that type (though other, non-const references to that type can modify the data).So 'final' will be a storage class and not a type modifier? That's one of the questions I still have with regards to your design, because I'm not seeing how 'final' can also not-be a type modifier. In particular, again, what is typeof(&foo) where foo is: final Foo foo; ?
Mar 24 2007
Bruno Medeiros wrote:Daniel Keep wrote:You are, of course, right. Damnit. Just when I thought I understood all this... :( -- Daniel -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/Bruno Medeiros wrote:No, that's not possible. It was mentioned before in another post: news://news.digitalmars.com:119/etv81l$m94$1 digitalmars.com Since invariant is (planned to be) transitive, then that typeof can't be (invariant Foo*), since the contents of foo can change (altough the immediate-value won't).Walter Bright wrote:I imagine it would be (invariant Foo*): an invariant pointer to a reference to a Foo. Since *no one* is ever allowed to change final storage, then a pointer to it must be invariant. -- DanielBruno has answered your specific questions, so I'll take a more general tack. A symbol is a name to which is 'bound' a value. static int x = 3; '3' is the value. 'int' is the type. 'x' is the symbol. 'static' is the storage class. Here, we bind a new value to the symbol x: x = 4; A storage class originally meant where the symbol is stored, such as in the data segment, on the stack, in a register, or in ROM. It's been generalized a bit since then. The main way to tell a storage class apart is that: 1) a storage class applies to the symbol 2) a type is independent of storage class, i.e. you cannot create a type that is "pointer to static" or "array of extern". Storage classes do not affect overloading, nor type deduction. 'invariant' and 'const' are type modifiers (aka type constructors), which mean when they are applied to a type, a new type is created that is a combination. 'invariant' is a guarantee that any data of that type will never change. 'const' is a guarantee that any data of that type will never be modified through a reference to that type (though other, non-const references to that type can modify the data).So 'final' will be a storage class and not a type modifier? That's one of the questions I still have with regards to your design, because I'm not seeing how 'final' can also not-be a type modifier. In particular, again, what is typeof(&foo) where foo is: final Foo foo; ?
Mar 24 2007
Walter Bright wrote:Andrei Alexandrescu (See Website For Email) wrote:Assuming that 'invariant' = really constant, 'const' = C++ pseudo-const... It's better than super const. However: (1) I would want to go through all my existing D code and change 100% of my usages of 'const' to 'invariant'. (2) although (1) could be avoided with the rule that 'const' on a declaration implicitly means 'invariant', this would then mean that to match a 'const' value, you use 'invariant'; but to match a non-const value, you use 'const'. That's horribly confusing. (3) I concede the problem of association with 'readonly' and ROM. But the association between 'const' and 'constant' is pretty strong. The problem remains that in: const int a = 2; void f(const int b) { } a really is a constant, but there is nothing constant about 'b'! How about 'protected'? It seems to cover the 'don't touch' meaning pretty well...kris wrote:I agree. I think: final const invariant for the three cases looks pretty good.So, "invariant" is already a keyword ... what about that?I completely missed that one. I think it's a good idea to look into it as a candidate for a qualifier name. Thank you.
Mar 19 2007
Don Clugston wrote:Assuming that 'invariant' = really constant, 'const' = C++ pseudo-const...Yah.It's better than super const. However: (1) I would want to go through all my existing D code and change 100% of my usages of 'const' to 'invariant'.Great to hear that!(2) although (1) could be avoided with the rule that 'const' on a declaration implicitly means 'invariant', this would then mean that to match a 'const' value, you use 'invariant'; but to match a non-const value, you use 'const'. That's horribly confusing.This I don't understand. Could you give an example?(3) I concede the problem of association with 'readonly' and ROM. But the association between 'const' and 'constant' is pretty strong.I think there's universal agreement that you can't express tersely the two notions "const-as-in-C++" and "const-as-in-we-really-mean-it". Probably it's best to just go with two terms and move on.The problem remains that in: const int a = 2; void f(const int b) { } a really is a constant, but there is nothing constant about 'b'!The code is incorrect. Const and invariant refer to indirectly-addressed memory. Probably you mean: final int a = 2; void f(final int b) { } The choice of "final" in the first case makes "a" bound to "2" for eternity. The choice of "final" in the second case prevents f from changing its argument, and it's the free will choice of f's author. The "final" does not influence f's signature or how other people use it. It's just constraining f's implementation. The two uses of "final" are reasonably consistent with one another.How about 'protected'? It seems to cover the 'don't touch' meaning pretty well...class Foo { protected: protected char[] find(protected char[] haystack, protected char[] needle); } 'Nuff said :o). Andrei
Mar 19 2007
Andrei Alexandrescu (See Website For Email) wrote:Don Clugston wrote:I think one of us misunderstood. I parsed that sentence as "I'd have to go through all my D code to keep it working properly", while judging by your reaction you seem to have parsed it as "I'd be happy to go through all my D code and make the necessary changes". (Note that the connotation(?) is a bit different; neutral/slightly negative vs quite positive)It's better than super const. However: (1) I would want to go through all my existing D code and change 100% of my usages of 'const' to 'invariant'.Great to hear that!
Mar 19 2007
Frits van Bommel wrote:Andrei Alexandrescu (See Website For Email) wrote:Well, I looked up "want" in my dictionary and parsed the sentence accordingly :o). AndreiDon Clugston wrote:I think one of us misunderstood. I parsed that sentence as "I'd have to go through all my D code to keep it working properly", while judging by your reaction you seem to have parsed it as "I'd be happy to go through all my D code and make the necessary changes". (Note that the connotation(?) is a bit different; neutral/slightly negative vs quite positive)It's better than super const. However: (1) I would want to go through all my existing D code and change 100% of my usages of 'const' to 'invariant'.Great to hear that!
Mar 19 2007
Andrei Alexandrescu (See Website For Email) wrote:Frits van Bommel wrote:Did you look up "would" as well? :P I read that to mean "if this was changed ..."Andrei Alexandrescu (See Website For Email) wrote:Well, I looked up "want" in my dictionary and parsed the sentence accordingly :o).Don Clugston wrote:I think one of us misunderstood. I parsed that sentence as "I'd have to go through all my D code to keep it working properly", while judging by your reaction you seem to have parsed it as "I'd be happy to go through all my D code and make the necessary changes". (Note that the connotation(?) is a bit different; neutral/slightly negative vs quite positive)It's better than super const. However: (1) I would want to go through all my existing D code and change 100% of my usages of 'const' to 'invariant'.Great to hear that!
Mar 19 2007
Andrei Alexandrescu (See Website For Email) wrote:Don Clugston wrote:Great perhaps, but it does suggest that 'const' should perhaps be the signifier for what 'invariant' has been proposed for (the literal meaning of each term notwithstanding)?Assuming that 'invariant' = really constant, 'const' = C++ pseudo-const...Yah.It's better than super const. However: (1) I would want to go through all my existing D code and change 100% of my usages of 'const' to 'invariant'.Great to hear that!invariant int* x; int* y; void fn( const int* z ) {} fn( x ); fn( y ); Assuming the above is legal, 'const' is the qualifier which binds to all reference types, ie. "to match a non-const value, you use 'const'."(2) although (1) could be avoided with the rule that 'const' on a declaration implicitly means 'invariant', this would then mean that to match a 'const' value, you use 'invariant'; but to match a non-const value, you use 'const'. That's horribly confusing.This I don't understand. Could you give an example?It's too bad too, since this word makes the most semantic sense :-) Sean(3) I concede the problem of association with 'readonly' and ROM. But the association between 'const' and 'constant' is pretty strong.I think there's universal agreement that you can't express tersely the two notions "const-as-in-C++" and "const-as-in-we-really-mean-it". Probably it's best to just go with two terms and move on.The problem remains that in: const int a = 2; void f(const int b) { } a really is a constant, but there is nothing constant about 'b'!The code is incorrect. Const and invariant refer to indirectly-addressed memory. Probably you mean: final int a = 2; void f(final int b) { } The choice of "final" in the first case makes "a" bound to "2" for eternity. The choice of "final" in the second case prevents f from changing its argument, and it's the free will choice of f's author. The "final" does not influence f's signature or how other people use it. It's just constraining f's implementation. The two uses of "final" are reasonably consistent with one another.How about 'protected'? It seems to cover the 'don't touch' meaning pretty well...class Foo { protected: protected char[] find(protected char[] haystack, protected char[] needle); } 'Nuff said :o).
Mar 19 2007
Sean Kelly wrote:Andrei Alexandrescu (See Website For Email) wrote:No. There will be far more uses for const than for invariant. You can take my word for that.Don Clugston wrote:Great perhaps, but it does suggest that 'const' should perhaps be the signifier for what 'invariant' has been proposed for (the literal meaning of each term notwithstanding)?Assuming that 'invariant' = really constant, 'const' = C++ pseudo-const...Yah.It's better than super const. However: (1) I would want to go through all my existing D code and change 100% of my usages of 'const' to 'invariant'.Great to hear that!That is correct. Andreiinvariant int* x; int* y; void fn( const int* z ) {} fn( x ); fn( y ); Assuming the above is legal, 'const' is the qualifier which binds to all reference types, ie. "to match a non-const value, you use 'const'."(2) although (1) could be avoided with the rule that 'const' on a declaration implicitly means 'invariant', this would then mean that to match a 'const' value, you use 'invariant'; but to match a non-const value, you use 'const'. That's horribly confusing.This I don't understand. Could you give an example?
Mar 19 2007
Andrei Alexandrescu (See Website For Email) wrote:Sean Kelly wrote:How about some further example? Given these sigs: struct Foo { int a; } class Bar { char[] b; } void fooish (inout Foo foo) {} char[] barish (Bar bar) {return bar.b;} 1) how do I modify the function decls to have the compiler *enforce* readonly upon the referenced content? e.g. Foo.a and Bar.b cannot be mutated within the function body? 2) how does the fooish() decl change to have the compiler *enforce* a readonly-view of the returned bar.b? 3) where fooish() has a Foo* rather than an inout Foo, is there any - KrisAndrei Alexandrescu (See Website For Email) wrote:No. There will be far more uses for const than for invariant. You can take my word for that.Don Clugston wrote:Great perhaps, but it does suggest that 'const' should perhaps be the signifier for what 'invariant' has been proposed for (the literal meaning of each term notwithstanding)?Assuming that 'invariant' = really constant, 'const' = C++ pseudo-const...Yah.It's better than super const. However: (1) I would want to go through all my existing D code and change 100% of my usages of 'const' to 'invariant'.Great to hear that!That is correct.invariant int* x; int* y; void fn( const int* z ) {} fn( x ); fn( y ); Assuming the above is legal, 'const' is the qualifier which binds to all reference types, ie. "to match a non-const value, you use 'const'."(2) although (1) could be avoided with the rule that 'const' on a declaration implicitly means 'invariant', this would then mean that to match a 'const' value, you use 'invariant'; but to match a non-const value, you use 'const'. That's horribly confusing.This I don't understand. Could you give an example?
Mar 19 2007
(Reposted after cleanup :o)) kris wrote:How about some further example? Given these sigs: struct Foo { int a; } class Bar { char[] b; } void fooish (inout Foo foo) {} char[] barish (Bar bar) {return bar.b;} 1) how do I modify the function decls to have the compiler *enforce* readonly upon the referenced content? e.g. Foo.a and Bar.b cannot be mutated within the function body?void fooish (const ref Foo foo) {} char[] barish (const Bar bar) {return bar.b;}2) how does the fooish() decl change to have the compiler *enforce* a readonly-view of the returned bar.b?const char[] barish (const Bar bar) {return bar.b;}3) where fooish() has a Foo* rather than an inout Foo, is there anyvoid fooish (const Foo* foo) {} By the way, a couple of days ago I've had an idea. Many people here ask for a "string" alias because char[] is a tad hard to type and uneasy on the eyes. Probably a good candidate would be: alias invariant char[] string; The resulting type is pretty damn slick: 1. You can alias it and slice it til you get blue in the face - no confusion ever, because nobody can overwrite the contents underneath your alias. 2. The EnsureCString(ref string) function will reallocate and copy the string at most once and only for a slice, never for the "original" string which was zero-terminated during construction. 3. The ~= operator works (somewhat surprisingly). 4. It's very, very rare that you want to modify some random character in a string, and when you do, use a char[] and then copy it back into a string, or rebuild the string from slices! 5. The Java experience (where String is immutable and StringBuffer is the mutable, build-me-piecemeal object) turned out to be largely successful, modulo syntax details that are not so elegant. 6. It meshes great with literals, which are exactly invariant arrays of characters: string hi = "Hello!"; // no dup needed! And it's 100% safe! So it looks like we have solved the string issue in an unexpectedly elegant way - by simply combining two features: invariant and array. Andrei
Mar 19 2007
Andrei Alexandrescu (See Website For Email) wrote:By the way, a couple of days ago I've had an idea. Many people here ask for a "string" alias because char[] is a tad hard to type and uneasy on the eyes. Probably a good candidate would be: alias invariant char[] string; The resulting type is pretty damn slick:...3. The ~= operator works (somewhat surprisingly).I assume this is because a char[] is actually a struct containing a pointer, so 'invariant' allows that pointer to be reassigned--it simply protects the referenced string? This is the sticking point for me. Assume we have this: struct Foo { int x; int* y; } const Foo foo; // is this legal? foo.x = 1; // this is allowed *foo.y = 2; // this is not allowed Is that correct, or do 'const' and 'invariant' truly only apply to pure reference types?4. It's very, very rare that you want to modify some random character in a string, and when you do, use a char[] and then copy it back into a string, or rebuild the string from slices!This may be true for a string, but for arrays in general I think this is fairly common.5. The Java experience (where String is immutable and StringBuffer is the mutable, build-me-piecemeal object) turned out to be largely successful, modulo syntax details that are not so elegant. 6. It meshes great with literals, which are exactly invariant arrays of characters: string hi = "Hello!"; // no dup needed! And it's 100% safe! So it looks like we have solved the string issue in an unexpectedly elegant way - by simply combining two features: invariant and array.Agreed. This is pretty nice :-) Sean
Mar 19 2007
Sean Kelly wrote:Andrei Alexandrescu (See Website For Email) wrote:That is correct. For an understanding of a ~= b, think of it as a = a ~ b. Do I modify the stuff indirectly referenced by "a"? No, Sir. I just rebind a to a larger entity that embeds a copy of its former self. In practice, the concatenation will not always produce a copy. The implementation will work "as if" you always produce a copy.By the way, a couple of days ago I've had an idea. Many people here ask for a "string" alias because char[] is a tad hard to type and uneasy on the eyes. Probably a good candidate would be: alias invariant char[] string; The resulting type is pretty damn slick:...3. The ~= operator works (somewhat surprisingly).I assume this is because a char[] is actually a struct containing a pointer, so 'invariant' allows that pointer to be reassigned--it simply protects the referenced string? This is the sticking point for me.Assume we have this: struct Foo { int x; int* y; } const Foo foo; // is this legal?Yes.foo.x = 1; // this is allowedYes.*foo.y = 2; // this is not allowedIt's not allowed.Is that correct, or do 'const' and 'invariant' truly only apply to pure reference types?No. They apply to any type that embeds references. "final" applies to all types and guards the bits of the symbol itself. "final const" guards symbol bits + referenced bits, and "final invariant" is as opposed to change as the 19th century British education system. (Did I get that right?)Yes. That's why arrays will stay in place :o). Andrei4. It's very, very rare that you want to modify some random character in a string, and when you do, use a char[] and then copy it back into a string, or rebuild the string from slices!This may be true for a string, but for arrays in general I think this is fairly common.
Mar 19 2007
Andrei Alexandrescu (See Website For Email) wrote:(Reposted after cleanup :o)) kris wrote:Hang on... wouldn't that need to be the signature of barish in the first place? If const is transitive, bar is declared as a const Bar and you're returning bar.b, isn't bar.b const as well?How about some further example? Given these sigs: struct Foo { int a; } class Bar { char[] b; } void fooish (inout Foo foo) {} char[] barish (Bar bar) {return bar.b;} 1) how do I modify the function decls to have the compiler *enforce* readonly upon the referenced content? e.g. Foo.a and Bar.b cannot be mutated within the function body?void fooish (const ref Foo foo) {} char[] barish (const Bar bar) {return bar.b;}2) how does the fooish() decl change to have the compiler *enforce* a readonly-view of the returned bar.b?const char[] barish (const Bar bar) {return bar.b;}You're a cruel, cruel man, Andrei. Now we're going to have to wait patiently for this... :'( Seriously, though, this is cool stuff. -- Daniel -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/3) where fooish() has a Foo* rather than an inout Foo, is there anyvoid fooish (const Foo* foo) {} By the way, a couple of days ago I've had an idea. Many people here ask for a "string" alias because char[] is a tad hard to type and uneasy on the eyes. Probably a good candidate would be: alias invariant char[] string; The resulting type is pretty damn slick: 1. You can alias it and slice it til you get blue in the face - no confusion ever, because nobody can overwrite the contents underneath your alias. 2. The EnsureCString(ref string) function will reallocate and copy the string at most once and only for a slice, never for the "original" string which was zero-terminated during construction. 3. The ~= operator works (somewhat surprisingly). 4. It's very, very rare that you want to modify some random character in a string, and when you do, use a char[] and then copy it back into a string, or rebuild the string from slices! 5. The Java experience (where String is immutable and StringBuffer is the mutable, build-me-piecemeal object) turned out to be largely successful, modulo syntax details that are not so elegant. 6. It meshes great with literals, which are exactly invariant arrays of characters: string hi = "Hello!"; // no dup needed! And it's 100% safe! So it looks like we have solved the string issue in an unexpectedly elegant way - by simply combining two features: invariant and array. Andrei
Mar 19 2007
Daniel Keep wrote:Andrei Alexandrescu (See Website For Email) wrote:"Nobody said all examples must compile" -- Andrei :o) Andrei(Reposted after cleanup :o)) kris wrote:Hang on... wouldn't that need to be the signature of barish in the first place? If const is transitive, bar is declared as a const Bar and you're returning bar.b, isn't bar.b const as well?How about some further example? Given these sigs: struct Foo { int a; } class Bar { char[] b; } void fooish (inout Foo foo) {} char[] barish (Bar bar) {return bar.b;} 1) how do I modify the function decls to have the compiler *enforce* readonly upon the referenced content? e.g. Foo.a and Bar.b cannot be mutated within the function body?void fooish (const ref Foo foo) {} char[] barish (const Bar bar) {return bar.b;}2) how does the fooish() decl change to have the compiler *enforce* a readonly-view of the returned bar.b?const char[] barish (const Bar bar) {return bar.b;}
Mar 19 2007
Andrei Alexandrescu (See Website For Email) wrote:(Reposted after cleanup :o)) kris wrote:would seem that the above answer permits an escaping mutable ref. I imagine that's not covered in the *cough* scope of the const domain since it can be sidestepped easily?How about some further example? Given these sigs: struct Foo { int a; } class Bar { char[] b; } void fooish (inout Foo foo) {} char[] barish (Bar bar) {return bar.b;} 1) how do I modify the function decls to have the compiler *enforce* readonly upon the referenced content? e.g. Foo.a and Bar.b cannot be mutated within the function body?void fooish (const ref Foo foo) {} char[] barish (const Bar bar) {return bar.b;}2) how does the fooish() decl change to have the compiler *enforce* a readonly-view of the returned bar.b?const char[] barish (const Bar bar) {return bar.b;}3) where fooish() has a Foo* rather than an inout Foo, is there anyvoid fooish (const Foo* foo) {}By the way, a couple of days ago I've had an idea. Many people here ask for a "string" alias because char[] is a tad hard to type and uneasy on the eyes. Probably a good candidate would be: alias invariant char[] string; The resulting type is pretty damn slick: 1. You can alias it and slice it til you get blue in the face - no confusion ever, because nobody can overwrite the contents underneath your alias. 2. The EnsureCString(ref string) function will reallocate and copy the string at most once and only for a slice, never for the "original" string which was zero-terminated during construction. 3. The ~= operator works (somewhat surprisingly). 4. It's very, very rare that you want to modify some random character in a string, and when you do, use a char[] and then copy it back into a string, or rebuild the string from slices! 5. The Java experience (where String is immutable and StringBuffer is the mutable, build-me-piecemeal object) turned out to be largely successful, modulo syntax details that are not so elegant. 6. It meshes great with literals, which are exactly invariant arrays of characters: string hi = "Hello!"; // no dup needed! And it's 100% safe! So it looks like we have solved the string issue in an unexpectedly elegant way - by simply combining two features: invariant and array.These are some of the reasons why a handful of us have been bitchin' about immutable views for so long. Regarding the alias, you'd likely have to consider w/dchar variations also ... it becomes a bit messy as things progress, which is one of the reasons we never had a string alias in the first place -- at least now there's more weight to the argument for an alias
Mar 19 2007
kris wrote:Andrei Alexandrescu (See Website For Email) wrote:Nobody said all examples must compile :o). In short, you won't be able to go const -> ~const without a cast, and the cast is never defined to harbor defined behavior.(Reposted after cleanup :o)) kris wrote:would seem that the above answer permits an escaping mutable ref. I imagine that's not covered in the *cough* scope of the const domain since it can be sidestepped easily?How about some further example? Given these sigs: struct Foo { int a; } class Bar { char[] b; } void fooish (inout Foo foo) {} char[] barish (Bar bar) {return bar.b;} 1) how do I modify the function decls to have the compiler *enforce* readonly upon the referenced content? e.g. Foo.a and Bar.b cannot be mutated within the function body?void fooish (const ref Foo foo) {} char[] barish (const Bar bar) {return bar.b;}2) how does the fooish() decl change to have the compiler *enforce* a readonly-view of the returned bar.b?const char[] barish (const Bar bar) {return bar.b;}3) where fooish() has a Foo* rather than an inout Foo, is there anyvoid fooish (const Foo* foo) {}Yah. Probably the aliases will come as a troika, string, wstring, and dstring (for lack of more inspired names). AndreiBy the way, a couple of days ago I've had an idea. Many people here ask for a "string" alias because char[] is a tad hard to type and uneasy on the eyes. Probably a good candidate would be: alias invariant char[] string; The resulting type is pretty damn slick: 1. You can alias it and slice it til you get blue in the face - no confusion ever, because nobody can overwrite the contents underneath your alias. 2. The EnsureCString(ref string) function will reallocate and copy the string at most once and only for a slice, never for the "original" string which was zero-terminated during construction. 3. The ~= operator works (somewhat surprisingly). 4. It's very, very rare that you want to modify some random character in a string, and when you do, use a char[] and then copy it back into a string, or rebuild the string from slices! 5. The Java experience (where String is immutable and StringBuffer is the mutable, build-me-piecemeal object) turned out to be largely successful, modulo syntax details that are not so elegant. 6. It meshes great with literals, which are exactly invariant arrays of characters: string hi = "Hello!"; // no dup needed! And it's 100% safe! So it looks like we have solved the string issue in an unexpectedly elegant way - by simply combining two features: invariant and array.These are some of the reasons why a handful of us have been bitchin' about immutable views for so long. Regarding the alias, you'd likely have to consider w/dchar variations also ... it becomes a bit messy as things progress, which is one of the reasons we never had a string alias in the first place -- at least now there's more weight to the argument for an alias
Mar 19 2007
On Mon, 19 Mar 2007 15:05:29 -0700, Andrei Alexandrescu (See Website For Email) wrote: I wish it wasn't so hard to get a simple straight answer from the experts. So far I think /The W&A Show/ is saying that 'const' and 'invariant' only apply to reference data types (objects, variable-length arrays, and pointers) and structs. They do not apply *in any way, shape or form* to any other data type. const char[] s; // ok const char c; // meaningless, the 'const' is ignored. const classFoo f; // okay const double* b; // okay; const double d; // meaningless, the 'const' is ignored. const structBar q; // okay 'const' means you cannot change the stuff the reference is referencing or the members of the struct, *but* for reference types you can change the reference value. s[0] = 'a'; // fails s = "new data"; //ok s.length = 2; // ok c = 'a'; // ok f.bar = 'a'; // fails f = new classFoo(); // okay *b = 1.0; // fails b = &someDouble; // ok d = 1.0; // okay q.foo = 'a'; // fails 'invariant' means you cannot change the stuff the reference is referencing or the members of the struct, *and* for reference types you cannot change the reference value. (If you one used 'invariant' rather than 'const' in above declarations...) s[0] = 'a'; // fails s = "new data"; // fails s.length = 2; // fails c = 'a'; // ok f.bar = 'a'; // fails f = new classFoo(); // fails *b = 1.0; // fails b = &someDouble; // fails d = 1.0; // okay q.foo = 'a'; // fails However, if this is the interpretation of 'invariant', how does one ever get to set the 'invariant' thing's value? invariant byte[] vCodes; . . . vCodes = LoadCodesFromFile(); // fails, no???By the way, a couple of days ago I've had an idea. Many people here ask for a "string" alias because char[] is a tad hard to type and uneasy on the eyes. Probably a good candidate would be: alias invariant char[] string; The resulting type is pretty damn slick: 1. You can alias it and slice it til you get blue in the face - no confusion ever, because nobody can overwrite the contents underneath your alias.void func( string s ) { string t; char[] u; u = s; u[0] = 'a'; // fails. u = s[1..4]; u[0] = 'a'; // fails u = s.dup; u[0] = 'a' // ok t = s; // fails??? }3. The ~= operator works (somewhat surprisingly).void func( string s ) { string t; char[] u; u ~= s; // ok s ~= 'a'; // fails ??? t ~= s; // fails??? }4. It's very, very rare that you want to modify some random character in a string, and when you do, use a char[] and then copy it back into a string, or rebuild the string from slices!It is not so rare in the type of applications that I do. Are you saying that I can do this...? string func( string s ) { char[] u; u = s.dup; u[somerandomspot] = 'a'; return u; } or this ... ? void func( string ref s ) { char[] u; u = s.dup; u[somerandomspot] = 'a'; s = u; } or this ... ? string func( string ref s ) { char[] u; string t; u = s.dup; u[somerandomspot] = 'a'; t = u; } What I don't get here is the phrase "copy it back into a string". This sounds ambiguous to me. It could mean, "construct a new string containing the updated data", or "replace the original string reference with a reference to the updated data". But I was starting to think that 'invariant' meant that you couldn't change the reference value at all, so I don't see how one could change an 'invariant' parameter or construct an 'invariant' local /variable/.So it looks like we have solved the string issue in an unexpectedly elegant way - by simply combining two features: invariant and array.I hope so. -- Derek (skype: derek.j.parnell) Melbourne, Australia "Justice for David Hicks!" 20/03/2007 9:28:14 AM
Mar 19 2007
Derek Parnell wrote:I wish it wasn't so hard to get a simple straight answer from the experts.It's not like anybody tries to obfuscate their writing.So far I think /The W&A Show/ is saying that 'const' and 'invariant' only apply to reference data types (objects, variable-length arrays, and pointers) and structs. They do not apply *in any way, shape or form* to any other data type. const char[] s; // ok const char c; // meaningless, the 'const' is ignored. const classFoo f; // okay const double* b; // okay; const double d; // meaningless, the 'const' is ignored. const structBar q; // okay 'const' means you cannot change the stuff the reference is referencing or the members of the struct, *but* for reference types you can change the reference value. s[0] = 'a'; // fails s = "new data"; //ok s.length = 2; // ok c = 'a'; // ok f.bar = 'a'; // fails f = new classFoo(); // okay *b = 1.0; // fails b = &someDouble; // ok d = 1.0; // okay q.foo = 'a'; // failsCorrect.'invariant' means you cannot change the stuff the reference is referencing or the members of the struct, *and* for reference types you cannot change the reference value.No. Invariant means that the data referenced indirectly is never modifiable by any part of the program. What you called 'invariant' above is 'final const'. [snip]However, if this is the interpretation of 'invariant', how does one ever get to set the 'invariant' thing's value? invariant byte[] vCodes; . . . vCodes = LoadCodesFromFile(); // fails, no???Right now you can only initialize invariant with literals. This aspect of the language is still under development. (Things like the result of some_string.dup also come to mind.)void func( string s ) { string t; char[] u; u = s; u[0] = 'a'; // fails. u = s[1..4]; u[0] = 'a'; // fails u = s.dup; u[0] = 'a' // ok t = s; // fails??? }You can't make the assignment u = s.s ~= a; works and is equivalent to s = s ~ a, i.e. "rebind s to the concatenation of s and a". It's an operation that does not mutate s's contents.3. The ~= operator works (somewhat surprisingly).void func( string s ) { string t; char[] u; u ~= s; // ok s ~= 'a'; // fails ??? t ~= s; // fails??? }You use char[] for that, and when you are done modifying, you can put things in a string.4. It's very, very rare that you want to modify some random character in a string, and when you do, use a char[] and then copy it back into a string, or rebuild the string from slices!It is not so rare in the type of applications that I do.Are you saying that I can do this...? string func( string s ) { char[] u; u = s.dup; u[somerandomspot] = 'a'; return u; }This is sound, but tricky to typecheck. I'll have to get back to you on that one.or this ... ? void func( string ref s ) { char[] u; u = s.dup; u[somerandomspot] = 'a'; s = u; }Same as above.or this ... ? string func( string ref s ) { char[] u; string t; u = s.dup; u[somerandomspot] = 'a'; t = u; }These last three examples work because u is temporary and not aliased with anything. If it were, the code would be unsound. Such cases are tricky to typecheck in the general case, but we'll look into a solution that allows such expressive idioms without also taking risks.What I don't get here is the phrase "copy it back into a string". This sounds ambiguous to me. It could mean, "construct a new string containing the updated data", or "replace the original string reference with a reference to the updated data". But I was starting to think that 'invariant' meant that you couldn't change the reference value at all, so I don't see how one could change an 'invariant' parameter or construct an 'invariant' local /variable/.Indeed, 'invariant' meant that the referenced data is invariant. The actual variable can be rebound to any other invariant data. It's like watching TV: you can always change your choice of watching, but you can't modify the actual contents of programs - unless you take special measures :o). Andrei
Mar 19 2007
On Mon, 19 Mar 2007 16:20:04 -0700, Andrei Alexandrescu (See Website For Email) wrote:Derek Parnell wrote:LOL ... I realize that. Some people are just naturals at it.I wish it wasn't so hard to get a simple straight answer from the experts.It's not like anybody tries to obfuscate their writing.YAY!!!! Finally something has sunk in to my head <G>So far I think /The W&A Show/ is saying that 'const' and 'invariant' only apply to reference data types (objects, variable-length arrays, and pointers) and structs. They do not apply *in any way, shape or form* to any other data type. const char[] s; // ok const char c; // meaningless, the 'const' is ignored. const classFoo f; // okay const double* b; // okay; const double d; // meaningless, the 'const' is ignored. const structBar q; // okay 'const' means you cannot change the stuff the reference is referencing or the members of the struct, *but* for reference types you can change the reference value. s[0] = 'a'; // fails s = "new data"; //ok s.length = 2; // ok c = 'a'; // ok f.bar = 'a'; // fails f = new classFoo(); // okay *b = 1.0; // fails b = &someDouble; // ok d = 1.0; // okay q.foo = 'a'; // failsCorrect.Hmmm ... so the difference between 'const' and 'invariant' is that const is only effective for one level deep, but 'invariant' is effective for all levels, right? struct Foo { int a; int* b; Foo c; Foo* d; } const Foo f_const; invariant Foo f_invar; int x; // assuming we can initialize f_const and f_invar at run time somehow, // then are the following subsequent assignments as stated? f_const.a = 1; // fails f_const.b = &x; // fails *f_const.b = 1; // okay; f_const.c.a = 1; // okay f_const.c.b = &x; // okay *f_const.c.b = 1; // okay f_const.d = new Foo; // fails f_const.d.a = 1; // okay f_const.d.b = &x; // okay *f_const.d.b = 1; // okay f_invar.a = 1; // fails f_invar.b = &x; // fails *f_invar.b = 1; // fails; f_invar.c.a = 1; // fails f_invar.c.b = &x; // fails *f_invar.c.b = 1; // fails f_invar.d = new Foo; // fails f_invar.d.a = 1; // fails f_invar.d.b = &x; // fails *f_invar.d.b = 1; // fails'invariant' means you cannot change the stuff the reference is referencing or the members of the struct, *and* for reference types you cannot change the reference value.No. Invariant means that the data referenced indirectly is never modifiable by any part of the program. What you called 'invariant' above is 'final const'.[snip]Oh ... okay. I'll wait for that mind bender then.However, if this is the interpretation of 'invariant', how does one ever get to set the 'invariant' thing's value? invariant byte[] vCodes; . . . vCodes = LoadCodesFromFile(); // fails, no???Right now you can only initialize invariant with literals. This aspect of the language is still under development. (Things like the result of some_string.dup also come to mind.)Oh, okay. The compiler will stop at "u = s;" because that would have made access to 's' data via the 'u' symbol. Got it.void func( string s ) { char[] u; u = s;You can't make the assignment u = s.So, could this be the mechanism to set an invariant array? invariant ubyte[] b; b ~= Load_Stuff_From_File();s ~= a; works and is equivalent to s = s ~ a, i.e. "rebind s to the concatenation of s and a". It's an operation that does not mutate s's contents.3. The ~= operator works (somewhat surprisingly).void func( string s ) { string t; char[] u; u ~= s; // ok s ~= 'a'; // fails ??? t ~= s; // fails??? }Oops. I was using "string" in the normal sense and not your new alias idea. In the context of the alias 'string' then what you say makes a lot of sense.You use char[] for that, and when you are done modifying, you can put things in a string.4. It's very, very rare that you want to modify some random character in a string, and when you do, use a char[] and then copy it back into a string, or rebuild the string from slices!It is not so rare in the type of applications that I do.It's like watching TV: you can always change your choice of watching(Not if my wife has the remote <G>) -- Derek (skype: derek.j.parnell) Melbourne, Australia "Justice for David Hicks!" 20/03/2007 10:53:00 AM
Mar 19 2007
Derek Parnell wrote:Hmmm ... so the difference between 'const' and 'invariant' is that const is only effective for one level deep, but 'invariant' is effective for all levels, right?Nonono. Const means: it might have originated as a variable, and somebody, somewhere, might hold a mutating reference to this and call it "my precious". Invariant is: nobody ever holds a mutating reference to it. Example: void Fun(const char[] a, char[] b) { char c = a[0]; b[0] = 'z'; assert(a[0] == c); // will fail } void main() { char[] x = "Wyda".dup; Fun(x, x); } Notice how the data referenced to by a is changing from under a's feet. Now let's rewrite Fun: void Gun(invariant char[] a, char[] b) { char c = a[0]; b[0] = 'z'; assert(a[0] == c); // never, ever, ever, ever fails } void main() { char[] x = "Wyda".dup; Fun(x, x); // can't compile! // mutating references can't be bound to invariant references } Andrei
Mar 19 2007
On Mon, 19 Mar 2007 17:50:28 -0700, Andrei Alexandrescu (See Website For Email) wrote:Derek Parnell wrote:Yeah ... but that's not what I was talking about. But be that as it may, it seems you are saying that the *only* difference between 'const' and 'invariant' is that 'invariant' means that every write attempt (direct and indirect) is denied, but 'const' only prevents direct write attempts. By 'direct' I mean explicitly using the symbol in the statement, and not another symbol that happens to contain the same address of the data. But I was talking earlier about the situation where something contains reference types or structs, and what effect 'const' and 'invariant' have on the things indirectly accessible via member data. struct Foo { char[] s; } void Func(const Foo fc, invariant Foo fi) { fc.s = "abc"; // fails ??? fc.s[0] = 'a'; // okay ??? fi.s = "abc"; // fails ??? fi.s[0] = 'a'; // fails ??? } Foo a; Foo b; Func(a,b); // fails ??? const Foo ac; const Foo bc; Func(ac,bc); // fails ??? invariant Foo ai; invariant Foo bi; Func(ai,bi); // fails ??? Func(ac,bi); // okay ??? -- Derek (skype: derek.j.parnell) Melbourne, Australia "Justice for David Hicks!" 20/03/2007 12:04:01 PMHmmm ... so the difference between 'const' and 'invariant' is that const is only effective for one level deep, but 'invariant' is effective for all levels, right?Nonono. Const means: it might have originated as a variable, and somebody, somewhere, might hold a mutating reference to this and call it "my precious". Invariant is: nobody ever holds a mutating reference to it.
Mar 19 2007
Derek Parnell wrote:On Mon, 19 Mar 2007 17:50:28 -0700, Andrei Alexandrescu (See Website For Email) wrote:Works. Understand that fc is the private copy owned by Func.Derek Parnell wrote:Yeah ... but that's not what I was talking about. But be that as it may, it seems you are saying that the *only* difference between 'const' and 'invariant' is that 'invariant' means that every write attempt (direct and indirect) is denied, but 'const' only prevents direct write attempts. By 'direct' I mean explicitly using the symbol in the statement, and not another symbol that happens to contain the same address of the data. But I was talking earlier about the situation where something contains reference types or structs, and what effect 'const' and 'invariant' have on the things indirectly accessible via member data. struct Foo { char[] s; } void Func(const Foo fc, invariant Foo fi) { fc.s = "abc"; // fails ???Hmmm ... so the difference between 'const' and 'invariant' is that const is only effective for one level deep, but 'invariant' is effective for all levels, right?Nonono. Const means: it might have originated as a variable, and somebody, somewhere, might hold a mutating reference to this and call it "my precious". Invariant is: nobody ever holds a mutating reference to it.fc.s[0] = 'a'; // okay ???Fails. fc would change bits not belonging to itself, and "const" makes those bits unchangeable.fi.s = "abc"; // fails ???Works. Modifies Func's own private copy of fi.fi.s[0] = 'a'; // fails ???Fails.} Foo a; Foo b; Func(a,b); // fails ???Fails. Can't bind modifiable b to an invariant Foo.const Foo ac; const Foo bc; Func(ac,bc); // fails ???Fails. Can't bind const b (which conservatively may be aliased to a modifiable view) to an invariant Foo.invariant Foo ai; invariant Foo bi; Func(ai,bi); // fails ???Works. No problem to bind ai to a const Foo.Func(ac,bi); // okay ???Perfect. Andrei
Mar 19 2007
Derek Parnell wrote:On Mon, 19 Mar 2007 15:05:29 -0700, Andrei Alexandrescu (See Website For Email) wrote: I wish it wasn't so hard to get a simple straight answer from the experts.I think discussion would much improved if big changes like this actually came with a detailed proposal on a website somewhere that people could refer to and which would actually be updated to reflect vague points clarified during discussion. As it is, there are a lot of points that have been clarified, and questions answered, but they're strewn across 100 different posts. I'm pretty lost. I gave up trying to follow this myself. I'm hoping you'll figure it out and post something coherent. :-) On the bright side, thanks to Andrei, at least there *is* an open discussion going on about the feature before it just shows up in the change log as a done deal. --bb
Mar 19 2007
Bill Baxter wrote:Derek Parnell wrote:I agree. (How couldn't I? Flattery goes a long way :o).) Maybe we could imitate what other languages do, e.g. Perl has the famous "apocalypses" that describe each language feature in detail. AndreiOn Mon, 19 Mar 2007 15:05:29 -0700, Andrei Alexandrescu (See Website For Email) wrote: I wish it wasn't so hard to get a simple straight answer from the experts.I think discussion would much improved if big changes like this actually came with a detailed proposal on a website somewhere that people could refer to and which would actually be updated to reflect vague points clarified during discussion. As it is, there are a lot of points that have been clarified, and questions answered, but they're strewn across 100 different posts. I'm pretty lost. I gave up trying to follow this myself. I'm hoping you'll figure it out and post something coherent. :-) On the bright side, thanks to Andrei, at least there *is* an open discussion going on about the feature before it just shows up in the change log as a done deal.
Mar 19 2007
Andrei Alexandrescu (See Website For Email) wrote:Bill Baxter wrote:I was thinking more of Python's PEPs, but yeh, same deal. I like PEPs in that anyone can submit one, get it assigned an offical number. As opposed to Larry's stone tablets brought down from the mountain top for the rest of us to ooh and ahh over. Python's way is a little more egalitarian. Semi-official Enhancement Proposals are also a good way to handle the many repeated requests for 'feature X'. Just tell 'em -- great idea, now go write a DEP for it. If they actually do it, then great. Next time someone asks for the feature you just point 'em to the previous DEP and the BFD ruling on it. My impression is that PEPs get weighted somehow based on how fleshed-out they are. For instance it seems a majority of PEPs (at least the ones I've read) come complete with prototype implementations. So PEP is more than just a vague wish like "Please implement Java-style serialization". It has to contain the nitty gritty details. --bbDerek Parnell wrote:I agree. (How couldn't I? Flattery goes a long way :o).) Maybe we could imitate what other languages do, e.g. Perl has the famous "apocalypses" that describe each language feature in detail.On Mon, 19 Mar 2007 15:05:29 -0700, Andrei Alexandrescu (See Website For Email) wrote: I wish it wasn't so hard to get a simple straight answer from the experts.I think discussion would much improved if big changes like this actually came with a detailed proposal on a website somewhere that people could refer to and which would actually be updated to reflect vague points clarified during discussion. As it is, there are a lot of points that have been clarified, and questions answered, but they're strewn across 100 different posts. I'm pretty lost. I gave up trying to follow this myself. I'm hoping you'll figure it out and post something coherent. :-) On the bright side, thanks to Andrei, at least there *is* an open discussion going on about the feature before it just shows up in the change log as a done deal.
Mar 19 2007
Bill Baxter wrote:Andrei Alexandrescu (See Website For Email) wrote:The PEP numbers are also a convenient way to refer to certain issues or features: "Oh the 'with' statement? That's PEP 343." The PEP can also serve as a starting point for the official documentation of the feature. Most importantly, they serve as a fixed locus of discussion, and can vastly improve the low signal-to-noise ratio that running around in circles on a mailing list or newsgroup can cause. In other words: DEPs++ -- Kirk McDonald http://kirkmcdonald.blogspot.com Pyd: Connecting D and Python http://pyd.dsource.orgBill Baxter wrote:I was thinking more of Python's PEPs, but yeh, same deal. I like PEPs in that anyone can submit one, get it assigned an offical number. As opposed to Larry's stone tablets brought down from the mountain top for the rest of us to ooh and ahh over. Python's way is a little more egalitarian. Semi-official Enhancement Proposals are also a good way to handle the many repeated requests for 'feature X'. Just tell 'em -- great idea, now go write a DEP for it. If they actually do it, then great. Next time someone asks for the feature you just point 'em to the previous DEP and the BFD ruling on it. My impression is that PEPs get weighted somehow based on how fleshed-out they are. For instance it seems a majority of PEPs (at least the ones I've read) come complete with prototype implementations. So PEP is more than just a vague wish like "Please implement Java-style serialization". It has to contain the nitty gritty details. --bbDerek Parnell wrote:I agree. (How couldn't I? Flattery goes a long way :o).) Maybe we could imitate what other languages do, e.g. Perl has the famous "apocalypses" that describe each language feature in detail.On Mon, 19 Mar 2007 15:05:29 -0700, Andrei Alexandrescu (See Website For Email) wrote: I wish it wasn't so hard to get a simple straight answer from the experts.I think discussion would much improved if big changes like this actually came with a detailed proposal on a website somewhere that people could refer to and which would actually be updated to reflect vague points clarified during discussion. As it is, there are a lot of points that have been clarified, and questions answered, but they're strewn across 100 different posts. I'm pretty lost. I gave up trying to follow this myself. I'm hoping you'll figure it out and post something coherent. :-) On the bright side, thanks to Andrei, at least there *is* an open discussion going on about the feature before it just shows up in the change log as a done deal.
Mar 19 2007
Kirk McDonald wrote:Bill Baxter wrote:I, too, think that's a great idea. AndreiAndrei Alexandrescu (See Website For Email) wrote:The PEP numbers are also a convenient way to refer to certain issues or features: "Oh the 'with' statement? That's PEP 343." The PEP can also serve as a starting point for the official documentation of the feature. Most importantly, they serve as a fixed locus of discussion, and can vastly improve the low signal-to-noise ratio that running around in circles on a mailing list or newsgroup can cause. In other words: DEPs++Bill Baxter wrote:I was thinking more of Python's PEPs, but yeh, same deal. I like PEPs in that anyone can submit one, get it assigned an offical number. As opposed to Larry's stone tablets brought down from the mountain top for the rest of us to ooh and ahh over. Python's way is a little more egalitarian. Semi-official Enhancement Proposals are also a good way to handle the many repeated requests for 'feature X'. Just tell 'em -- great idea, now go write a DEP for it. If they actually do it, then great. Next time someone asks for the feature you just point 'em to the previous DEP and the BFD ruling on it. My impression is that PEPs get weighted somehow based on how fleshed-out they are. For instance it seems a majority of PEPs (at least the ones I've read) come complete with prototype implementations. So PEP is more than just a vague wish like "Please implement Java-style serialization". It has to contain the nitty gritty details. --bbDerek Parnell wrote:I agree. (How couldn't I? Flattery goes a long way :o).) Maybe we could imitate what other languages do, e.g. Perl has the famous "apocalypses" that describe each language feature in detail.On Mon, 19 Mar 2007 15:05:29 -0700, Andrei Alexandrescu (See Website For Email) wrote: I wish it wasn't so hard to get a simple straight answer from the experts.I think discussion would much improved if big changes like this actually came with a detailed proposal on a website somewhere that people could refer to and which would actually be updated to reflect vague points clarified during discussion. As it is, there are a lot of points that have been clarified, and questions answered, but they're strewn across 100 different posts. I'm pretty lost. I gave up trying to follow this myself. I'm hoping you'll figure it out and post something coherent. :-) On the bright side, thanks to Andrei, at least there *is* an open discussion going on about the feature before it just shows up in the change log as a done deal.
Mar 19 2007
On Tue, 20 Mar 2007 08:29:31 +0900, Bill Baxter wrote:On the bright side, thanks to Andrei, at least there *is* an open discussion going on about the feature before it just shows up in the change log as a done deal.Amen to that. A *HUGE* thank you to Andrei for being so available and willing to suffer fools gladly. This discussions extremely important for everybody an the big W just can't do it all. -- Derek (skype: derek.j.parnell) Melbourne, Australia "Justice for David Hicks!" 20/03/2007 10:49:22 AM
Mar 19 2007
Derek Parnell wrote:On Tue, 20 Mar 2007 08:29:31 +0900, Bill Baxter wrote:I thank you folks. Sharing is great. Studying alone is learning from a fool. AndreiOn the bright side, thanks to Andrei, at least there *is* an open discussion going on about the feature before it just shows up in the change log as a done deal.Amen to that. A *HUGE* thank you to Andrei for being so available and willing to suffer fools gladly. This discussions extremely important for everybody an the big W just can't do it all.
Mar 19 2007
Derek Parnell Wrote:const char[] s; // ok ... s[0] = 'a'; // fails s = "new data"; //ok s.length = 2; // okNo, it can not. const int[] a = [1, 2, 3, 4]; a.length = 2; // ok? some_var = a[3]; // oops! But length is not field. jovo
Mar 20 2007
jovo Wrote:Derek Parnell Wrote:Ooops! :) May be it's more logical then I was thinking. There are will be always tension between consistency, convenience and efficiency of generated code. Actually I like general D's approach. jovoconst char[] s; // ok ... s[0] = 'a'; // fails s = "new data"; //ok s.length = 2; // okNo, it can not. const int[] a = [1, 2, 3, 4]; a.length = 2; // ok? some_var = a[3]; // oops!
Mar 20 2007
Andrei Alexandrescu (See Website For Email) wrote:By the way, a couple of days ago I've had an idea. Many people here ask for a "string" alias because char[] is a tad hard to type and uneasy on the eyes. Probably a good candidate would be: alias invariant char[] string;Now that I like. Reminds me very much of Python. -- Kirk McDonald http://kirkmcdonald.blogspot.com Pyd: Connecting D and Python http://pyd.dsource.org
Mar 19 2007
Andrei Alexandrescu (See Website For Email) Wrote:(Reposted after cleanup :o)) kris wrote:void fooish(const ref Foo foo) { foo.a = 1; // not allowed foo = sam_Foo; // allowed? jovoHow about some further example? Given these sigs: struct Foo { int a; } class Bar { char[] b; } void fooish (inout Foo foo) {} char[] barish (Bar bar) {return bar.b;} 1) how do I modify the function decls to have the compiler *enforce* readonly upon the referenced content? e.g. Foo.a and Bar.b cannot be mutated within the function body?void fooish (const ref Foo foo) {}
Mar 20 2007
jovo wrote:Andrei Alexandrescu (See Website For Email) Wrote:Not allowed indeed.(Reposted after cleanup :o)) kris wrote:void fooish(const ref Foo foo) { foo.a = 1; // not allowedHow about some further example? Given these sigs: struct Foo { int a; } class Bar { char[] b; } void fooish (inout Foo foo) {} char[] barish (Bar bar) {return bar.b;} 1) how do I modify the function decls to have the compiler *enforce* readonly upon the referenced content? e.g. Foo.a and Bar.b cannot be mutated within the function body?void fooish (const ref Foo foo) {}foo = sam_Foo; // allowed?Not allowed. The type of foo is const(ref(Foo)). When you try to assign to foo, you'll assign to indirectly referenced bits. If you only replace Foo with int (which makes sense because Foo is a struct), you'll see how trying to assign the int would indirectly modify memory outside the function. Now consider: void Fun(ref const Foo foo) { } The type of foo is ref(const(Foo)). So the function has a reference to a constant object. It can modify the direct fields of the object, but nothing beyond that. It's not a very useful case. We might even choose to prohibit it statically unless compelling use cases show up. I actually already think of a couple :o). Andrei
Mar 20 2007
Andrei Alexandrescu (See Website For Email) wrote:Don Clugston wrote:Sorry, I didn't explain myself very well. I meant that this proposal breaks 100% of all existing D uses of const. >> (3) I concede the problem of association with 'readonly' and ROM. ButAssuming that 'invariant' = really constant, 'const' = C++ pseudo-const...Yah.It's better than super const. However: (1) I would want to go through all my existing D code and change 100% of my usages of 'const' to 'invariant'.Great to hear that!I completely agree with this. The gripe I have is that 'const' is a completely inappropriate term for 'const-as-in-C++'. It's a bizarre misnomer to use 'const' to mean "don't touch". The only benefit (albeit a considerable one) of this nomenclature is compatibility with C++ nomenclature, especially the term "const correctness". D currently has a 'const' which actually means "constant", it seems dreadful to exchange that for a clearly inferior "don't touch" meaning. I'm concerned that you may have spent so much time in C++ that you've become accustomed to "const" == "don't touch"; all of my previous posts have been arguing that this is a grossly unnatural association. It is possible that the C++ misnomer is so entrenched that D needs to perpetuate it, even at the expense of breaking all existing D code that uses 'const'. But then this really surprises me:the association between 'const' and 'constant' is pretty strong.I think there's universal agreement that you can't express tersely the two notions "const-as-in-C++" and "const-as-in-we-really-mean-it". Probably it's best to just go with two terms and move on.final int a = 2; void f(final int b) { } The choice of "final" in the second case prevents f from changing its argument, and it's the free will choice of f's author. The "final" does not influence f's signature or how other people use it. It's just constraining f's implementation.because it seems that that we still have 'const' surprises for C++ refugees.
Mar 20 2007
Don Clugston wrote:Andrei Alexandrescu (See Website For Email) wrote:Ah, so I /did/ read that right.Don Clugston wrote:Sorry, I didn't explain myself very well. I meant that this proposal breaks 100% of all existing D uses of const.It's better than super const. However: (1) I would want to go through all my existing D code and change 100% of my usages of 'const' to 'invariant'.Great to hear that!>> (3) I concede the problem of association with 'readonly' and ROM. ButI completely agree with *that* :).I completely agree with this. The gripe I have is that 'const' is a completely inappropriate term for 'const-as-in-C++'. It's a bizarre misnomer to use 'const' to mean "don't touch". The only benefit (albeit a considerable one) of this nomenclature is compatibility with C++ nomenclature, especially the term "const correctness". D currently has a 'const' which actually means "constant", it seems dreadful to exchange that for a clearly inferior "don't touch" meaning. I'm concerned that you may have spent so much time in C++ that you've become accustomed to "const" == "don't touch"; all of my previous posts have been arguing that this is a grossly unnatural association.the association between 'const' and 'constant' is pretty strong.I think there's universal agreement that you can't express tersely the two notions "const-as-in-C++" and "const-as-in-we-really-mean-it". Probably it's best to just go with two terms and move on.It is possible that the C++ misnomer is so entrenched that D needs to perpetuate it, even at the expense of breaking all existing D code that uses 'const'.And I really hope this is not the case.But then this really surprises me:I don't see how this would be a surprise for anyone coming from C++. This is exactly how 'const' works for value types, isn't it? (Do this with reference types on the other hand, and I could see them being a bit confused) The thing to keep in mind is that 'b' is a new variable (kept on the stack) that happens to have the same value as whatever was passed to the function. If that variable happens not to be changed by the code where it's in scope, that doesn't effect other code in any way at all. In other words: There's no way to tell the difference from outside of the function, so why would it change the signature?final int a = 2; void f(final int b) { } The choice of "final" in the second case prevents f from changing its argument,> and it's the free will choice of f's author. The "final" does not > influence f's signature or how other people use it. > It's just constraining f's implementation. because it seems that that we still have 'const' surprises for C++ refugees.
Mar 20 2007
Frits van Bommel wrote:Don Clugston wrote:Yes. The point is that for some uses of C++ const, you have to use 'const', while for others you need to use 'final'. I feel that this weakens the argument for using the word 'const' in the C++ sense. The hypothetical C++ refugee is still going to have culture shock when using D const.But then this really surprises me:I don't see how this would be a surprise for anyone coming from C++. This is exactly how 'const' works for value types, isn't it?final int a = 2; void f(final int b) { } The choice of "final" in the second case prevents f from changing its argument,> and it's the free will choice of f's author. The "final" does not > influence f's signature or how other people use it. > It's just constraining f's implementation. because it seems that that we still have 'const' surprises for C++ refugees.
Mar 20 2007
Don Clugston wrote:Frits van Bommel wrote:I think the shock will be mollified by the explanation that const is for the stuff "before the star" and final is for the stuff "after the star". const char *const s = "hello"; // C++ Many C++ programmers complain about this syntax, finding it silly. AndreiDon Clugston wrote:Yes. The point is that for some uses of C++ const, you have to use 'const', while for others you need to use 'final'. I feel that this weakens the argument for using the word 'const' in the C++ sense. The hypothetical C++ refugee is still going to have culture shock when using D const.But then this really surprises me:I don't see how this would be a surprise for anyone coming from C++. This is exactly how 'const' works for value types, isn't it?final int a = 2; void f(final int b) { } The choice of "final" in the second case prevents f from changing its argument,> and it's the free will choice of f's author. The "final" does not > influence f's signature or how other people use it. > It's just constraining f's implementation. because it seems that that we still have 'const' surprises for C++ refugees.
Mar 20 2007
Andrei Alexandrescu (See Website For Email) wrote:I think the shock will be mollified by the explanation that const is for the stuff "before the star" and final is for the stuff "after the star". const char *const s = "hello"; // C++ Many C++ programmers complain about this syntax, finding it silly.I also have to always stop and think about what it means. Const in C++ actually has 3 distinct meanings, and which is in force depends on the context. In my discussions about this with C++ programmers, even C++ compiler implementors, very, very few understand just what is going on with C++ const. I think a lot of the confusion here about const is coming from the misunderstandings engendered by the C++ mechanism. What the D proposal does is identify those 3 distinct meanings, and make them distinct and individually controllable. This should also, in the long run, make it more understandable once one is able to get past the wacky confusion that is C++ const. It also gives those who care about const-correctness the mechanism to control precisely what they need, and it can even help the optimizer generate better code. (C++ const is worthless for generating better code.)
Mar 20 2007
Andrei Alexandrescu (See Website For Email) wrote:Don Clugston wrote:Huh? Wait a second, but won't D have the same issue, albeit with 'final'? For example, suppose you have: final Foo foo; then what is: typeof(&foo) ? -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DFrits van Bommel wrote:I think the shock will be mollified by the explanation that const is for the stuff "before the star" and final is for the stuff "after the star". const char *const s = "hello"; // C++ Many C++ programmers complain about this syntax, finding it silly. AndreiDon Clugston wrote:Yes. The point is that for some uses of C++ const, you have to use 'const', while for others you need to use 'final'. I feel that this weakens the argument for using the word 'const' in the C++ sense. The hypothetical C++ refugee is still going to have culture shock when using D const.But then this really surprises me:I don't see how this would be a surprise for anyone coming from C++. This is exactly how 'const' works for value types, isn't it?final int a = 2; void f(final int b) { } The choice of "final" in the second case prevents f from changing its argument,> and it's the free will choice of f's author. The "final" does not > influence f's signature or how other people use it. > It's just constraining f's implementation. because it seems that that we still have 'const' surprises for C++ refugees.
Mar 20 2007
Bruno Medeiros wrote:Huh? Wait a second, but won't D have the same issue, albeit with 'final'? For example, suppose you have: final Foo foo; then what is: typeof(&foo) ?invariant Foo* or const Foo*, depending on whichever is most appropriate for the situation. I'd guess that invariant Foo* would be the default because it's semantically closest to what is being expressed (a pointer to immutable data), though const Foo* is also allowable because you can't modify data through const pointers either.
Mar 20 2007
Tyler Knott wrote:Bruno Medeiros wrote:As I understand, there will be an implicit cast of mutables to immutables, so assuming 'const' appears under 'invariant' in this list, I would expect|hope it to be 'const Foo*' so that it is passable to either 'const' or 'invariant' typed parameters. Ie: final Foo foo; void alpha (invariant Foo x) {...} void beta (const Foo x) {...} auto ptr = &foo; alpha(*foo); // no problem regardless beta(*foo); // an issue if ptr is invariant Again, this is /if/ the casting rules will be as I think they will. I'm just now starting to wrap my own head around it. Presumably if I really /want/ it to be invariant, I could maybe do this? invariant ptr = &foo; Which would perform the mentioned implicit cast before assignment, discarding the potential 'const' view. -- Chris Nicholson-SaulsHuh? Wait a second, but won't D have the same issue, albeit with 'final'? For example, suppose you have: final Foo foo; then what is: typeof(&foo) ?invariant Foo* or const Foo*, depending on whichever is most appropriate for the situation. I'd guess that invariant Foo* would be the default because it's semantically closest to what is being expressed (a pointer to immutable data), though const Foo* is also allowable because you can't modify data through const pointers either.
Mar 20 2007
Chris Nicholson-Sauls wrote:As I understand, there will be an implicit cast of mutables to immutables, so assuming 'const' appears under 'invariant' in this list, I would expect|hope it to be 'const Foo*' so that it is passable to either 'const' or 'invariant' typed parameters. Ie:Actually, I take back what I said in my previous post in this thread. Taking the address of a final variable should always result in an invariant pointer. The reason is that invariant references require the data they reference to never, ever change whereas const references expect the data they reference to be changed by other non-const/non-immutable references to that data. Obviously, since const references can't guarantee the data they reference won't change they can't be cast to immutable references at all, but because const references can still guarantee they won't mutate the data they reference immutable references can be freely cast to const references.
Mar 20 2007
Tyler Knott wrote:Chris Nicholson-Sauls wrote:Well, yes, but is 'invariant' transitive like const? I think it is (but I'm not sure, I'm getting a bit lost in the thread), and if it is, those semantics won't work. I.e., "typeof(&foo) " in my example can't be invariant anything. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DAs I understand, there will be an implicit cast of mutables to immutables, so assuming 'const' appears under 'invariant' in this list, I would expect|hope it to be 'const Foo*' so that it is passable to either 'const' or 'invariant' typed parameters. Ie:Actually, I take back what I said in my previous post in this thread. Taking the address of a final variable should always result in an invariant pointer. The reason is that invariant references require the data they reference to never, ever change whereas const references expect the data they reference to be changed by other non-const/non-immutable references to that data. Obviously, since const references can't guarantee the data they reference won't change they can't be cast to immutable references at all, but because const references can still guarantee they won't mutate the data they reference immutable references can be freely cast to const references.
Mar 22 2007
Bruno Medeiros wrote:Well, yes, but is 'invariant' transitive like const? I think it is (but I'm not sure, I'm getting a bit lost in the thread), and if it is, those semantics won't work. I.e., "typeof(&foo) " in my example can't be invariant anything.D'oh, of course! It's legal to modify data referenced by foo, which makes it incompatible with invariant pointers, but which is fine for const pointers. I think const pointer is the correct answer for typeof(&foo).
Mar 22 2007
Bruno Medeiros wrote:Tyler Knott wrote:Actually, having thought over it a few times, what I would really expect is not a "const pointer to a Foo", but rather a "const(pointer to a Foo)"... final Foo foo; auto ptr = &foo; // const(Foo*) Hmm. Baffling. I almost give up. -- Chris Nicholson-SaulsChris Nicholson-Sauls wrote:Well, yes, but is 'invariant' transitive like const? I think it is (but I'm not sure, I'm getting a bit lost in the thread), and if it is, those semantics won't work. I.e., "typeof(&foo) " in my example can't be invariant anything.As I understand, there will be an implicit cast of mutables to immutables, so assuming 'const' appears under 'invariant' in this list, I would expect|hope it to be 'const Foo*' so that it is passable to either 'const' or 'invariant' typed parameters. Ie:Actually, I take back what I said in my previous post in this thread. Taking the address of a final variable should always result in an invariant pointer. The reason is that invariant references require the data they reference to never, ever change whereas const references expect the data they reference to be changed by other non-const/non-immutable references to that data. Obviously, since const references can't guarantee the data they reference won't change they can't be cast to immutable references at all, but because const references can still guarantee they won't mutate the data they reference immutable references can be freely cast to const references.
Mar 23 2007
Chris Nicholson-Sauls wrote:Bruno Medeiros wrote:Don't. It's entirely understandable to be confused. Extremely little information has been given to date. Once that information will come in proper book format, it will be very easy to understand. AndreiTyler Knott wrote:Actually, having thought over it a few times, what I would really expect is not a "const pointer to a Foo", but rather a "const(pointer to a Foo)"... final Foo foo; auto ptr = &foo; // const(Foo*) Hmm. Baffling. I almost give up.Chris Nicholson-Sauls wrote:Well, yes, but is 'invariant' transitive like const? I think it is (but I'm not sure, I'm getting a bit lost in the thread), and if it is, those semantics won't work. I.e., "typeof(&foo) " in my example can't be invariant anything.As I understand, there will be an implicit cast of mutables to immutables, so assuming 'const' appears under 'invariant' in this list, I would expect|hope it to be 'const Foo*' so that it is passable to either 'const' or 'invariant' typed parameters. Ie:Actually, I take back what I said in my previous post in this thread. Taking the address of a final variable should always result in an invariant pointer. The reason is that invariant references require the data they reference to never, ever change whereas const references expect the data they reference to be changed by other non-const/non-immutable references to that data. Obviously, since const references can't guarantee the data they reference won't change they can't be cast to immutable references at all, but because const references can still guarantee they won't mutate the data they reference immutable references can be freely cast to const references.
Mar 23 2007
Tyler Knott wrote:Bruno Medeiros wrote:Let's suppose it's const Foo* (the less restrictive option). Even so, you will be restricting the type more than necessary, thus loosing some range of freedom. Because with const Foo* you can't change members of Foo*, while with final Foo, you can change members of foo. I.e.: final Foo foo; foo.x = 2; // ok typeof(&foo) fooptr = &foo; (*fooptr.x) = 2; // not allowed -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DHuh? Wait a second, but won't D have the same issue, albeit with 'final'? For example, suppose you have: final Foo foo; then what is: typeof(&foo) ?invariant Foo* or const Foo*, depending on whichever is most appropriate for the situation. I'd guess that invariant Foo* would be the default because it's semantically closest to what is being expressed (a pointer to immutable data), though const Foo* is also allowable because you can't modify data through const pointers either.
Mar 22 2007
Bruno Medeiros wrote:Tyler Knott wrote:I guess the only way to solve that is to parameterise const and invariant...Bruno Medeiros wrote:Let's suppose it's const Foo* (the less restrictive option). Even so, you will be restricting the type more than necessary, thus loosing some range of freedom. Because with const Foo* you can't change members of Foo*, while with final Foo, you can change members of foo. I.e.: final Foo foo; foo.x = 2; // ok typeof(&foo) fooptr = &foo; (*fooptr.x) = 2; // not allowedHuh? Wait a second, but won't D have the same issue, albeit with 'final'? For example, suppose you have: final Foo foo; then what is: typeof(&foo) ?invariant Foo* or const Foo*, depending on whichever is most appropriate for the situation. I'd guess that invariant Foo* would be the default because it's semantically closest to what is being expressed (a pointer to immutable data), though const Foo* is also allowable because you can't modify data through const pointers either.final Foo foo; final invariant Foo bar; writefln("%s", typeinfo(typeof(&foo))); writefln("%s", typeinfo(typeof(&bar))); --> invariant(1) Foo invariant(*) FooHonestly, I don't think that's going to happen :P -- Daniel -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
Mar 22 2007
Daniel Keep wrote:Bruno Medeiros wrote:No, another way to solve that is to have 'final' be a type modifier as well: typeof(&foo) --> (final Foo)* This is essentially exactly like C++'s 'const'. (and like the 'rdonly' in my "hobbyist" design.) -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DTyler Knott wrote:I guess the only way to solve that is to parameterise const and invariant...Bruno Medeiros wrote:Let's suppose it's const Foo* (the less restrictive option). Even so, you will be restricting the type more than necessary, thus loosing some range of freedom. Because with const Foo* you can't change members of Foo*, while with final Foo, you can change members of foo. I.e.: final Foo foo; foo.x = 2; // ok typeof(&foo) fooptr = &foo; (*fooptr.x) = 2; // not allowedHuh? Wait a second, but won't D have the same issue, albeit with 'final'? For example, suppose you have: final Foo foo; then what is: typeof(&foo) ?invariant Foo* or const Foo*, depending on whichever is most appropriate for the situation. I'd guess that invariant Foo* would be the default because it's semantically closest to what is being expressed (a pointer to immutable data), though const Foo* is also allowable because you can't modify data through const pointers either.final Foo foo; final invariant Foo bar; writefln("%s", typeinfo(typeof(&foo))); writefln("%s", typeinfo(typeof(&bar))); --> invariant(1) Foo invariant(*) FooHonestly, I don't think that's going to happen :P -- Daniel
Mar 23 2007
Bruno Medeiros wrote:Daniel Keep wrote:I think the problem with that is that final pi = 3.1415...; then doesn't do what you think it does. If pi is now of type final real, then you would still be able to re-assign it. final e = 2.14...; pi = e; We probably *could* make it so that you can't assign to a variable that's got a final'ed type, but then it's acting like a storage class, not as a type. I dunno. This whole thread is just giving me a headache... I *thought* I understood it after the first post, but now my head hurts and I'm not so sure :P -- Daniel -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/Bruno Medeiros wrote:No, another way to solve that is to have 'final' be a type modifier as well: typeof(&foo) --> (final Foo)* This is essentially exactly like C++'s 'const'. (and like the 'rdonly' in my "hobbyist" design.)Tyler Knott wrote:I guess the only way to solve that is to parameterise const and invariant...Bruno Medeiros wrote:Let's suppose it's const Foo* (the less restrictive option). Even so, you will be restricting the type more than necessary, thus loosing some range of freedom. Because with const Foo* you can't change members of Foo*, while with final Foo, you can change members of foo. I.e.: final Foo foo; foo.x = 2; // ok typeof(&foo) fooptr = &foo; (*fooptr.x) = 2; // not allowedHuh? Wait a second, but won't D have the same issue, albeit with 'final'? For example, suppose you have: final Foo foo; then what is: typeof(&foo) ?invariant Foo* or const Foo*, depending on whichever is most appropriate for the situation. I'd guess that invariant Foo* would be the default because it's semantically closest to what is being expressed (a pointer to immutable data), though const Foo* is also allowable because you can't modify data through const pointers either.final Foo foo; final invariant Foo bar; writefln("%s", typeinfo(typeof(&foo))); writefln("%s", typeinfo(typeof(&bar))); --> invariant(1) Foo invariant(*) FooHonestly, I don't think that's going to happen :P -- Daniel
Mar 23 2007
Don Clugston wrote:I completely agree with this. The gripe I have is that 'const' is a completely inappropriate term for 'const-as-in-C++'. It's a bizarre misnomer to use 'const' to mean "don't touch". The only benefit (albeit a considerable one) of this nomenclature is compatibility with C++ nomenclature, especially the term "const correctness". D currently has a 'const' which actually means "constant", it seems dreadful to exchange that for a clearly inferior "don't touch" meaning. I'm concerned that you may have spent so much time in C++ that you've become accustomed to "const" == "don't touch"; all of my previous posts have been arguing that this is a grossly unnatural association. It is possible that the C++ misnomer is so entrenched that D needs to perpetuate it, even at the expense of breaking all existing D code that uses 'const'.I agree with Don here. -- Lars Ivar Igesund blog at http://larsivi.net DSource, #d.tango & #D: larsivi Dancing the Tango
Mar 20 2007
Lars Ivar Igesund wrote:Don Clugston wrote:So do I Was somewhat hoping invariant would be used in place of what has now taken shape as "const", and "constant" would be used in place of where "invariant" has landed. Then there would be no "const" to confuse anyone. Almost seems as though shortening the name by a couple of bytes is actually more important than the meaning of the words in use? I'm not sure about "breaking all existing D code" ... there would seem to be very little use of "const" at this time, because the current semantics are really kinda worthless; e.g. one should probably use enum for most things 'constant', except you can't have "enum : char[]" making enum notably less useful than it could otherwise be. Where does enum fit in this picture anyway? Can it recover some duty from "const" and/or "final" in a logical and consistent manner?I completely agree with this. The gripe I have is that 'const' is a completely inappropriate term for 'const-as-in-C++'. It's a bizarre misnomer to use 'const' to mean "don't touch". The only benefit (albeit a considerable one) of this nomenclature is compatibility with C++ nomenclature, especially the term "const correctness". D currently has a 'const' which actually means "constant", it seems dreadful to exchange that for a clearly inferior "don't touch" meaning. I'm concerned that you may have spent so much time in C++ that you've become accustomed to "const" == "don't touch"; all of my previous posts have been arguing that this is a grossly unnatural association. It is possible that the C++ misnomer is so entrenched that D needs to perpetuate it, even at the expense of breaking all existing D code that uses 'const'.I agree with Don here.
Mar 20 2007
kris wrote:Lars Ivar Igesund wrote:I think the 5 letters to 9 letters a difference, especially when repeated many times. And again: invariant and const are synonims. Merriam-Webster lists "constant" as the first meaning of "invariant": http://m-w.com/dictionary/invariantDon Clugston wrote:So do I Was somewhat hoping invariant would be used in place of what has now taken shape as "const", and "constant" would be used in place of where "invariant" has landed. Then there would be no "const" to confuse anyone. Almost seems as though shortening the name by a couple of bytes is actually more important than the meaning of the words in use?I completely agree with this. The gripe I have is that 'const' is a completely inappropriate term for 'const-as-in-C++'. It's a bizarre misnomer to use 'const' to mean "don't touch". The only benefit (albeit a considerable one) of this nomenclature is compatibility with C++ nomenclature, especially the term "const correctness". D currently has a 'const' which actually means "constant", it seems dreadful to exchange that for a clearly inferior "don't touch" meaning. I'm concerned that you may have spent so much time in C++ that you've become accustomed to "const" == "don't touch"; all of my previous posts have been arguing that this is a grossly unnatural association. It is possible that the C++ misnomer is so entrenched that D needs to perpetuate it, even at the expense of breaking all existing D code that uses 'const'.I agree with Don here.I'm not sure about "breaking all existing D code" ... there would seem to be very little use of "const" at this time, because the current semantics are really kinda worthless; e.g. one should probably use enum for most things 'constant', except you can't have "enum : char[]" making enum notably less useful than it could otherwise be. Where does enum fit in this picture anyway? Can it recover some duty from "const" and/or "final" in a logical and consistent manner?If I had my way, I'd make the language powerful enough to express enumerated types in stdlib, then I'd deprecate the built-in one. Andrei
Mar 20 2007
Andrei Alexandrescu (See Website For Email) wrote:kris wrote:[snip]Yeah, I know. Except there's three flies in the ointment: 1) you've already suggested "const" won't get used all that much (or can be implied/inferred instead). 2) Then there's the question of whether "constant" is a more appropriate term for what "invariant" is slated to do. 3) Additionally, it may well be better to dump "const" altogether simply to alleviate potential confusion. It's hardly a life or death scenario, yet the choices being made really do appear to be slanted towards "something" that just doesn't seem entirely sensibleWas somewhat hoping invariant would be used in place of what has now taken shape as "const", and "constant" would be used in place of where "invariant" has landed. Then there would be no "const" to confuse anyone. Almost seems as though shortening the name by a couple of bytes is actually more important than the meaning of the words in use?I think the 5 letters to 9 letters a difference, especially when repeated many times. And again: invariant and const are synonims. Merriam-Webster lists "constant" as the first meaning of "invariant": http://m-w.com/dictionary/invariantWould be good to make the type system more flexible and extensible, but that's getting away from the point: enum represents 'constant' values, so presumably has some bearing upon this discussion?I'm not sure about "breaking all existing D code" ... there would seem to be very little use of "const" at this time, because the current semantics are really kinda worthless; e.g. one should probably use enum for most things 'constant', except you can't have "enum : char[]" making enum notably less useful than it could otherwise be. Where does enum fit in this picture anyway? Can it recover some duty from "const" and/or "final" in a logical and consistent manner?If I had my way, I'd make the language powerful enough to express enumerated types in stdlib, then I'd deprecate the built-in one.
Mar 20 2007
Don Clugston wrote:Andrei Alexandrescu (See Website For Email) wrote:I don't think so. Const becomes less precise, but maybe code wasn't using it with all the precision anyway. I actually suspect the new semantics will break very little code.Don Clugston wrote:Sorry, I didn't explain myself very well. I meant that this proposal breaks 100% of all existing D uses of const.Assuming that 'invariant' = really constant, 'const' = C++ pseudo-const...Yah.It's better than super const. However: (1) I would want to go through all my existing D code and change 100% of my usages of 'const' to 'invariant'.Great to hear that!>> (3) I concede the problem of association with 'readonly' and ROM. ButThe problem is that we don't have a "nomer". Every good short name we considered would be as imprecise or more. There's no obvious choice that everybody's like, "those idiots! why did they _refuse_ to do it that way?" And it's telling that every single person who didn't like "const" with the intended meaning failed to come with an obviously better choice.I completely agree with this. The gripe I have is that 'const' is a completely inappropriate term for 'const-as-in-C++'. It's a bizarre misnomer to use 'const' to mean "don't touch".the association between 'const' and 'constant' is pretty strong.I think there's universal agreement that you can't express tersely the two notions "const-as-in-C++" and "const-as-in-we-really-mean-it". Probably it's best to just go with two terms and move on.The only benefit (albeit a considerable one) of this nomenclature is compatibility with C++ nomenclature, especially the term "const correctness".Right. Imagine us coming with the "dontouch correctness" :o).D currently has a 'const' which actually means "constant", it seems dreadful to exchange that for a clearly inferior "don't touch" meaning.It's not "inferior". If it were inferior, we'd take it out of the language. Today's "const" semantics are restrictive in ways that severely limit its usefulness (e.g. you can't pass data modifiable in a module to functions guaranteed to NOT modify data in another module). The new const will allow that, and that's great. It's not inferior.I'm concerned that you may have spent so much time in C++ that you've become accustomed to "const" == "don't touch"; all of my previous posts have been arguing that this is a grossly unnatural association.I completely hear you. Yet you are failing to follow with, "...when it's so obvious to everyone that the natural association is..."It is possible that the C++ misnomer is so entrenched that D needs to perpetuate it, even at the expense of breaking all existing D code that uses 'const'. But then this really surprises me:We can make "const" mean "final const" and drop "final", at the cost of disallowing correct code (e.g. functions that modify their own private parameters). Or we could come up with new syntax that puts "const" in a different position for array, e.g.: void Fun(const char[] const s); After considering such alternatives, final becomes much more attractive. Andreifinal int a = 2; void f(final int b) { } The choice of "final" in the second case prevents f from changing its argument,> and it's the free will choice of f's author. The "final" does not > influence f's signature or how other people use it. > It's just constraining f's implementation. because it seems that that we still have 'const' surprises for C++ refugees.
Mar 20 2007
Andrei Alexandrescu (See Website For Email) wrote: <snip>We can make "const" mean "final const" and drop "final", at the cost of disallowing correct code (e.g. functions that modify their own private parameters). Or we could come up with new syntax that puts "const" in a different position for array, e.g.: void Fun(const char[] const s); After considering such alternatives, final becomes much more attractive.I think someone, sometime mentioned changing the meaning of the 'in' keyword. I guess that would have the same meaning with functions parameters that is planned for const now? void Fun(in char[] s); // Fun can't modify the array contents void Fun(const char[] s); // 'in' looks nice here char* strcpy(char* to, in char* from); char* strcpy(char* to, const char* from); // let's say this returns the number of irreversibly converted chars, like iconv does. size_t utf8ToLatin1(in char[] from, out ubyte[] to); size_t utf8ToLatin1(const char[] from, out ubyte[] to); One obvious problem is that in and out would not be really opposites. 'out' and 'inout' would take the address of the argument, but 'in' does nothing of the sort. Maybe that could be confusing.
Mar 20 2007
Andrei Alexandrescu (See Website For Email) wrote:Don Clugston wrote:Actually, I have not tried to come up with a better choice. I still think 'readonly' captures it pretty well. I've changed my mind about the validity of the argument about "it's not obvious which means truly constant, 'const' or 'readonly'" since I feel that it applies just as strongly to 'const' vs 'invariant'. My intuition would be that 'invariant' means read-only. The usage of 'invariant' in design-by-contract is for something that can be modified temporarily but must ultimately be preserved; this is weaker than 'constant'.Andrei Alexandrescu (See Website For Email) wrote:The problem is that we don't have a "nomer". Every good short name we considered would be as imprecise or more. There's no obvious choice that everybody's like, "those idiots! why did they _refuse_ to do it that way?" And it's telling that every single person who didn't like "const" with the intended meaning failed to come with an obviously better choice.I think there's universal agreement that you can't express tersely the two notions "const-as-in-C++" and "const-as-in-we-really-mean-it". Probably it's best to just go with two terms and move on.I completely agree with this. The gripe I have is that 'const' is a completely inappropriate term for 'const-as-in-C++'. It's a bizarre misnomer to use 'const' to mean "don't touch".I'm arguing about the name, not the semantics. The use of 'const' in the original post has caused no end of confusion, since it is different from the current D const. To rephrase: 'const' is a very appropriate word for what 'const' does in D now: it defines a constant. The proposed const has an inferior connection to the word 'constant'. Actually, there's a feature of the existing const which seems to be missing in the new proposal. Currently, if you have const int x = 4; it is illegal to write &x. (just as it is illegal to write &4). This means that the existing const cannot be subverted, even by asm code. (#define x 4 is similar, except untyped). Can you do this with the new proposal?The only benefit (albeit a considerable one) of this nomenclature is compatibility with C++ nomenclature, especially the term "const correctness".Right. Imagine us coming with the "dontouch correctness" :o).D currently has a 'const' which actually means "constant", it seems dreadful to exchange that for a clearly inferior "don't touch" meaning.It's not "inferior". If it were inferior, we'd take it out of the language. Today's "const" semantics are restrictive in ways that severely limit its usefulness (e.g. you can't pass data modifiable in a module to functions guaranteed to NOT modify data in another module). The new const will allow that, and that's great. It's not inferior.The natural association is "const" == "never changes, under any circumstances". "readonly" == "don't touch". Even for read-only memory, if you've ever used an EPROM burner, or flashed firmware, you know that someone can write to it. I've changed readonly memory, I've never changed a constant. The concept of 'read-only' access is pretty widely understood.I'm concerned that you may have spent so much time in C++ that you've become accustomed to "const" == "don't touch"; all of my previous posts have been arguing that this is a grossly unnatural association.I completely hear you. Yet you are failing to follow with, "...when it's so obvious to everyone that the natural association is..."
Mar 21 2007
Don Clugston wrote:The natural association is "const" == "never changes, under any circumstances". "readonly" == "don't touch". Even for read-only memory, if you've ever used an EPROM burner, or flashed firmware, you know that someone can write to it. I've changed readonly memory, I've never changed a constant. The concept of 'read-only' access is pretty widely understood.I dunno about that. Yes if you're talking about physical constants or constants like Pi, they never ever change. But 'constant' is also used frequently in mathematics to mean something that's simply "not variable in the current context". Like when doing partial differentiation with respect to y, all variables besides y are treated as constants. And if you don't agree with me, the very first section of the Wikipedia on "Constant" (http://en.wikipedia.org/wiki/Constant) talks about "unspecified constants", referring to parts of an equation that simply aren't variables. But you can definitely change them if you want (the example they use is the Pythagorean theorem). They are only constant for one particular instance of the problem. Even if the Wikipedia article is way off base (the Pythagorean theorem seems a very odd choice to demonstrate the concept of 'constant') the fact that such text managed to make it onto Wikipedia indicates that the common understanding of the word "constant" includes more territory than you're apparently allowing for. Also your definition of constant (i.e. something like Pi which absolutely cannot change) seems to be a more a replacement for the proposed 'final' as in 'final Pi = 3.14;' than for a reference whose referent cannot change. So personally I'm of the opinion we should pick two words that make at least a modicum of sense in English, forget about what they might mean in C++ or Java or whatever, make sure the common one is short, easy to type, and easy on the eyes, and just go with it. --bb
Mar 21 2007
Bill Baxter wrote:Don Clugston wrote:I discussed that already. The proposed 'const' is variable in the current context, since (for example) another thread can change it. If you read a value described as 'const', then read it again later, it is not safe to assume that it has not changed. Therefore, it is not constant in any meaningful sense.The natural association is "const" == "never changes, under any circumstances". "readonly" == "don't touch". Even for read-only memory, if you've ever used an EPROM burner, or flashed firmware, you know that someone can write to it. I've changed readonly memory, I've never changed a constant. The concept of 'read-only' access is pretty widely understood.I dunno about that. Yes if you're talking about physical constants or constants like Pi, they never ever change. But 'constant' is also used frequently in mathematics to mean something that's simply "not variable in the current context". Like when doing partial differentiation with respect to y, all variables besides y are treated as constants.Also your definition of constant (i.e. something like Pi which absolutely cannot change) seems to be a more a replacement for the proposed 'final' as in 'final Pi = 3.14;' than for a reference whose referent cannot change.True. I just can't see much use for 'const' as a keyword.So personally I'm of the opinion we should pick two words that make at least a modicum of sense in English, forget about what they might mean in C++ or Java or whatever, make sure the common one is short, easy to type, and easy on the eyes, and just go with it. --bb
Mar 22 2007
Don Clugston wrote:Andrei Alexandrescu (See Website For Email) wrote:Indeed, and seems to represent a misunderstand of what const *does* mean in C++. In this context: int const x(3); it means "x is constant, i.e., cannot be changed". In this context: int const *y(&x); it means "y is a pointer to a (possibly constant) int". Without the const, y would not be allowed to point to a constant int. It doesn't mean "don't touch" -- it means "cannot be used to alter", i.e., "leaves const if indeed it was const". It's closer to "won't touch". It's clear though that the meaning confuses too many people. What's not clear to me is whether the proposed terminology for D is any better. Certainly much of the discussion seems to be based on misstatements of how C++ works. There's scope to do better than C++, but it does require understanding that on which we hope to improve. -- JamesDon Clugston wrote:Sorry, I didn't explain myself very well. I meant that this proposal breaks 100% of all existing D uses of const. >> (3) I concede the problem of association with 'readonly' and ROM. ButAssuming that 'invariant' = really constant, 'const' = C++ pseudo-const...Yah.It's better than super const. However: (1) I would want to go through all my existing D code and change 100% of my usages of 'const' to 'invariant'.Great to hear that!I completely agree with this. The gripe I have is that 'const' is a completely inappropriate term for 'const-as-in-C++'. It's a bizarre misnomer to use 'const' to mean "don't touch".the association between 'const' and 'constant' is pretty strong.I think there's universal agreement that you can't express tersely the two notions "const-as-in-C++" and "const-as-in-we-really-mean-it". Probably it's best to just go with two terms and move on.
Mar 20 2007
Walter Bright escribi:Andrei Alexandrescu (See Website For Email) wrote:I haven't finished reading everything on this thread yet, so I don't know if this has been asked. Also, I'm failing to fully understand this, but I still have this question: how would the following be understood by the compiler? class A { invariant { int a = 4; float b = -10; } } What is that? A class invariant or two invariant class members? (If the latter even makes sense at all...) -- Carlos Santander Bernalkris wrote:I agree. I think: final const invariant for the three cases looks pretty good.So, "invariant" is already a keyword ... what about that?I completely missed that one. I think it's a good idea to look into it as a candidate for a qualifier name. Thank you.
Mar 19 2007
Andrei Alexandrescu (See Website For Email) wrote:Deewiant wrote:If you just want something that sounds like more const than const using existing keywords, there are other options: 'true const' 'double const' 'finally const' 'is const' or 'is finally super double true const' I kinda like 'true const' myself. Sounds less dorky than super const to me. :-) --bbBenji Smith wrote:Working in NLP myself, I totally disagree. Natural language is rife with homonimy and synonimy, and we're all very, very happy with that. But in this case we don't even have to go that far: "super" is an adjective meaning primarily "of high grade or quality" and qualifies a noun. If there's no noun, you don't know what is "of high grade or quality". It's a fact, and we don't even blink. The reality behind super const is that it expresses a stronger form of const. It makes a lot of sense if I dub it "super const" in natural language, to express it in the same way in the programming language. I thought that that's too verbose and devised "const!" as a shortcut (again with obvious conotations in natural language), but I'm thinking of dropping it and let type inference add "super" to "const" whenever it can. That should ensure exactness of the type system without verbosity in source code.And the word "super" is now overloaded in two completely unrelated concepts.Which isn't that rare, see the following link: http://www.prowiki.org/wiki4d/wiki.cgi?LanguageSpecification/KeywordIndex I find the following examples: auto, in, is, mixin, scope, static. I have come to abhor the keyword "static" largely due to the above. Too bad its various uses are unavoidably useful. <g> But I do agree with you, in a way. After writing the following I find my explanation somewhat unclear even to myself, but bear with me. The problem with "super const" is that "super" modifies the other keyword, "const", instead of saying something about the expression/statement/whatever (in this case, the type). Even "static", in all its horror, can be seen as specifying one of "module-level" or "compile-time". The other keywords mentioned above use their English meaning as such an explanation, and so can be understood without too much thought. "super const" would make "super" another "static": lacking context, you can't be sure about about even the general meaning, let alone the one in a specific instance. Upon reflection it may be moot, since one probably rarely cares about keywords' meanings without context, but I'm sure some psychologist could come up with something about intuitiveness which affects coding speed, or whatever.I'd be happiest to just get the feature as soon as possible; worrying about keyword semantics can come later. Just like the abominations beginning with "on_scope_". <g>Great idea. :o) Andrei
Mar 16 2007
Benji Smith wrote:Andrei Alexandrescu (See Website For Email) wrote:I think that sums up my take on this pretty well. Thanks for saving me the typing :).We've shoved keywords like "readonly" and "view" for a while, and they just added more confusion than cleared, at a high cost. If (as I suspect) super const appears relatively infrequently, it might be fine to just encode it as the mildly verbose "super const". In fact, it's shorter than "keepyourgrubbyhandsoff". :o) AndreiReally? I'd think super const would be used all the time. Anywhere a class has some invariant field, it'll probably be expressed as super const (if I'm understanding correctly that super const is the equivalent of #define constants in C++ or static final constants in Java). Let me join the ranks of those who hate both versions of the new syntax. const! looks either like a template or like "not const". You guys may think you're saving a keyword, and that might be technically correct from the perspective of the parser. But, for the perspective of the D developer, it still looks like you've introduced a new keyword, but it's a keyword that's A) nearly identical to another keyword, and B) contains a symbol. Ugh. I really. Really. Really. Hate it. Using "super const" is also annoying because all of the other storage classes use a single keyword. Now we've got this weird case that uses two keywords. And the word "super" is now overloaded in two completely unrelated concepts. (By the way, I don't like "static if" either. I think the right choice would have been #if, #foreach, etc. And I think C++ made a mistake by defining "long long" and "double double" types as well. Presumably, that saved some keywords, but we'd all have been better off if the types were defined as int8, int16, int32, int64, float32, float64, etc). I vote for "readonly" and "const". Anything else seems like a mistake.
Mar 16 2007
I should also add that, in my opinion, any design where "const" means something other than "value resolved at compile time and immutable at runtime" would be a mistake. (I'm not crazy about using "const" to mean "value resolved at runtime, and immutable after its first assignment", but I don't hate it either.) --benji
Mar 16 2007
Benji Smith wrote:I should also add that, in my opinion, any design where "const" means something other than "value resolved at compile time and immutable at runtime" would be a mistake.Then how would you call "value that's not mutable through this alias" in a way that's not going to turn C++ immigrants away? Andrei
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Benji Smith wrote:there are explicit names for that sort of thing; "immutable", "readonly" , "view" etc. Reading through the various replies gives the impression that you're concerned about propogating the broken C++ semantics than ensuring D corrects those faults ;) I think it's worthwhile ensuring D gets it right instead, and I'll happily change all of Tango to reflect that if necessary. Breaking source-code for a keyword that is currently used rarely is not a problem. Incorrect or dubious/confusing semantics are. It may be worthwhile dumping the "const" keyword altogether, to limit confusion. BTW, you've also mentioned changing "inout" to "ref" instead? That would probably break more code than a renaming of const; I know both Tango and Mango use inout quite a bit, but I'm happy to change those as necessary. Other people likely feel the same way. - KrisI should also add that, in my opinion, any design where "const" means something other than "value resolved at compile time and immutable at runtime" would be a mistake.Then how would you call "value that's not mutable through this alias" in a way that's not going to turn C++ immigrants away?
Mar 16 2007
kris wrote:Andrei Alexandrescu (See Website For Email) wrote:++vote For what it's worth, I like: 'final', 'view', and 'const' the best. They're all short and meaningful, given the intent for each. SeanBenji Smith wrote:there are explicit names for that sort of thing; "immutable", "readonly" , "view" etc. Reading through the various replies gives the impression that you're concerned about propogating the broken C++ semantics than ensuring D corrects those faults ;) I think it's worthwhile ensuring D gets it right instead, and I'll happily change all of Tango to reflect that if necessary. Breaking source-code for a keyword that is currently used rarely is not a problem. Incorrect or dubious/confusing semantics are. It may be worthwhile dumping the "const" keyword altogether, to limit confusion. BTW, you've also mentioned changing "inout" to "ref" instead? That would probably break more code than a renaming of const; I know both Tango and Mango use inout quite a bit, but I'm happy to change those as necessary. Other people likely feel the same way.I should also add that, in my opinion, any design where "const" means something other than "value resolved at compile time and immutable at runtime" would be a mistake.Then how would you call "value that's not mutable through this alias" in a way that's not going to turn C++ immigrants away?
Mar 16 2007
Sean Kelly wrote:For what it's worth, I like: 'final', 'view', and 'const' the best. They're all short and meaningful, given the intent for each.The problem with 'view' is that it's a noun, while final and const are adjectives. It's very awkward to use 'view': view int * p = &x; // huh? Andrei
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Sean Kelly wrote:yuh, fair point :(For what it's worth, I like: 'final', 'view', and 'const' the best. They're all short and meaningful, given the intent for each.The problem with 'view' is that it's a noun, while final and const are adjectives. It's very awkward to use 'view': view int * p = &x; // huh?
Mar 16 2007
On Fri, 16 Mar 2007 14:03:13 -0700, Andrei Alexandrescu (See Website For Email) wrote:Sean Kelly wrote:As in "to view or not to view, that is the question" <g>For what it's worth, I like: 'final', 'view', and 'const' the best. They're all short and meaningful, given the intent for each.The problem with 'view' is that it's a noun,while final and const are adjectives.So how does the argument from NLP about 'super' being used to qualify nouns sound now?It's very awkward to use 'view': view int * p = &x; // huh?But this isn't ... ? super const int * p = &x; How about ... const int * const p = &x; -- Derek Parnell Melbourne, Australia "Justice for David Hicks!" skype: derek.j.parnell
Mar 16 2007
Derek Parnell wrote:On Fri, 16 Mar 2007 14:03:13 -0700, Andrei Alexandrescu (See Website For Email) wrote:I must not see the connection. "super const int" is a suggestive collocation; "view int" is not.Sean Kelly wrote:As in "to view or not to view, that is the question" <g>For what it's worth, I like: 'final', 'view', and 'const' the best. They're all short and meaningful, given the intent for each.The problem with 'view' is that it's a noun,while final and const are adjectives.So how does the argument from NLP about 'super' being used to qualify nouns sound now?That's final and expresses something entirely different. AndreiIt's very awkward to use 'view': view int * p = &x; // huh?But this isn't ... ? super const int * p = &x; How about ... const int * const p = &x;
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Sean Kelly wrote:It's probably not terribly helpful, but 'view' is also a verb. SeanFor what it's worth, I like: 'final', 'view', and 'const' the best. They're all short and meaningful, given the intent for each.The problem with 'view' is that it's a noun, while final and const are adjectives. It's very awkward to use 'view': view int * p = &x; // huh?
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Sean Kelly wrote:How about this? Using existing keywords, with a rename of "const": 1) final - rebinding of a value to a name 2) invariant - a read-only view of a data structure 3) constant - a value that never changesFor what it's worth, I like: 'final', 'view', and 'const' the best. They're all short and meaningful, given the intent for each.The problem with 'view' is that it's a noun, while final and const are adjectives. It's very awkward to use 'view': view int * p = &x; // huh?
Mar 16 2007
kris wrote:How about this? Using existing keywords, with a rename of "const": 1) final - rebinding of a value to a name 2) invariant - a read-only view of a data structure 3) constant - a value that never changesActually, that's pretty good too. Getting rid of the keyword "const" would definitely highlight that something is different between D's const-ness and the const-ness in other (anachronistic ;-) ) languages. --benji
Mar 16 2007
kris wrote:How about this? Using existing keywords, with a rename of "const": 1) final - rebinding of a value to a name[moved '2)']3) constant - a value that never changesThese two are fine by me.2) invariant - a read-only view of a data structureNo. Just No. For one thing, the data structure can vary :) : anyone with a mutable reference can change the value from under your nose, so "does not vary" simply isn't applicable here. But more importantly, invariant has a very clear and defined meaning in computer science. It should not be overloaded like this.
Mar 16 2007
Frits van Bommel wrote:kris wrote:Much of the terminological problem is that it's hard to express const's imprecision (as opposed to super const's precision) tersely. One of my ideas was using "const" for truly set in stone, and using "const?" to mean that the object may or may not have originated as const. But code with question marks everywhere would look odd. AndreiHow about this? Using existing keywords, with a rename of "const": 1) final - rebinding of a value to a name[moved '2)']3) constant - a value that never changesThese two are fine by me. > 2) invariant - a read-only view of a data structure No. Just No. For one thing, the data structure can vary :) : anyone with a mutable reference can change the value from under your nose, so "does not vary" simply isn't applicable here. But more importantly, invariant has a very clear and defined meaning in computer science. It should not be overloaded like this.
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Sean Kelly wrote:And 'view' is also probably a very popular name for a variable thanks to things like the "Model-View-Controller" paradigm. http://www.google.com/codesearch?q=view&hl=en&btnG=Search+Code --bbFor what it's worth, I like: 'final', 'view', and 'const' the best. They're all short and meaningful, given the intent for each.The problem with 'view' is that it's a noun, while final and const are adjectives. It's very awkward to use 'view': view int * p = &x; // huh? Andrei
Mar 16 2007
Bill Baxter wrote:Andrei Alexandrescu (See Website For Email) wrote:However, viewonly is a possibility that's particularly expressive. As much as I'm wary of collapsed words, this is the contender I like the most. It's a bit long though, and given that it's also the most heavily used, it would lead to long lines. But, as Walter put it very wisely: addressing immutability is a big problem, and syntax is only a fraction of it. AndreiSean Kelly wrote:And 'view' is also probably a very popular name for a variable thanks to things like the "Model-View-Controller" paradigm. http://www.google.com/codesearch?q=view&hl=en&btnG=Search+CodeFor what it's worth, I like: 'final', 'view', and 'const' the best. They're all short and meaningful, given the intent for each.The problem with 'view' is that it's a noun, while final and const are adjectives. It's very awkward to use 'view': view int * p = &x; // huh? Andrei
Mar 16 2007
kris wrote:BTW, you've also mentioned changing "inout" to "ref" instead? That would probably break more code than a renaming of const; I know both Tango and Mango use inout quite a bit, but I'm happy to change those as necessary. Other people likely feel the same way.Changing inout to ref would be a very long process in several stages: 1) Adding ref as a keyword and documenting its usage 2) Recommending changing usage from 'inout' to 'ref' 3) Removing 'inout' from the documentation 4) Producing a warning on 'inout' with -w switch 5) Deprecating 'inout' 6) Removing 'inout' as keyword Also, 'inout' is easily greppable, and very likely is unique enough that using nothing more than a global search/replace will work.
Mar 16 2007
Walter Bright wrote:kris wrote:I will notice that that process didn't start for the infamous magic variable "length". It's still in http://digitalmars.com/d/expression.html :o(. AndreiBTW, you've also mentioned changing "inout" to "ref" instead? That would probably break more code than a renaming of const; I know both Tango and Mango use inout quite a bit, but I'm happy to change those as necessary. Other people likely feel the same way.Changing inout to ref would be a very long process in several stages: 1) Adding ref as a keyword and documenting its usage 2) Recommending changing usage from 'inout' to 'ref' 3) Removing 'inout' from the documentation 4) Producing a warning on 'inout' with -w switch 5) Deprecating 'inout' 6) Removing 'inout' as keyword Also, 'inout' is easily greppable, and very likely is unique enough that using nothing more than a global search/replace will work.
Mar 16 2007
Walter Bright wrote:kris wrote:Why not just stop at '1'? Inout is very descriptive if what you're planning to do is modify the input in a way that the caller can see the changes. Just make it a synonym for 'ref'. And instead of telling people not to use it, tell them to use it only when inout behavior is the actual intent. Otherwise use 'const ref'. And make 'const inout' be an error. But in terms of the syntax tree generated, both 'inout' and 'ref' will be 'ref's. --bbBTW, you've also mentioned changing "inout" to "ref" instead? That would probably break more code than a renaming of const; I know both Tango and Mango use inout quite a bit, but I'm happy to change those as necessary. Other people likely feel the same way.Changing inout to ref would be a very long process in several stages: 1) Adding ref as a keyword and documenting its usage 2) Recommending changing usage from 'inout' to 'ref' 3) Removing 'inout' from the documentation 4) Producing a warning on 'inout' with -w switch 5) Deprecating 'inout' 6) Removing 'inout' as keyword Also, 'inout' is easily greppable, and very likely is unique enough that using nothing more than a global search/replace will work.
Mar 16 2007
Bill Baxter wrote:Walter Bright wrote:That's very awkward. Exact synonyms fare real bad in all languages I know. It's chaff without any nutritional benefit. Everybody would have preferred that "=>" in Perl is something different from ",", or that template<typename T> and template<class T> would be different things in C++. Andreikris wrote:Why not just stop at '1'? Inout is very descriptive if what you're planning to do is modify the input in a way that the caller can see the changes. Just make it a synonym for 'ref'. And instead of telling people not to use it, tell them to use it only when inout behavior is the actual intent. Otherwise use 'const ref'. And make 'const inout' be an error.BTW, you've also mentioned changing "inout" to "ref" instead? That would probably break more code than a renaming of const; I know both Tango and Mango use inout quite a bit, but I'm happy to change those as necessary. Other people likely feel the same way.Changing inout to ref would be a very long process in several stages: 1) Adding ref as a keyword and documenting its usage 2) Recommending changing usage from 'inout' to 'ref' 3) Removing 'inout' from the documentation 4) Producing a warning on 'inout' with -w switch 5) Deprecating 'inout' 6) Removing 'inout' as keyword Also, 'inout' is easily greppable, and very likely is unique enough that using nothing more than a global search/replace will work.
Mar 16 2007
On Fri, 16 Mar 2007 11:48:47 -0700, kris wrote:... but I'm happy to change those as necessary. Other people likely feel the same way.I am more than happy to change my source code if the result is easier to read and an improved D. -- Derek Parnell Melbourne, Australia "Justice for David Hicks!" skype: derek.j.parnell
Mar 16 2007
kris wrote:Andrei Alexandrescu (See Website For Email) wrote:No, just no gratuitous incompatibilities and misunderstanding. For example, "readonly" reminds some of ROM, which is really immutable. Then, "view" is too common a word to steal it as a keyword. Finally, "immutable" is again ambiguous.Benji Smith wrote:there are explicit names for that sort of thing; "immutable", "readonly" , "view" etc. Reading through the various replies gives the impression that you're concerned about propogating the broken C++ semantics than ensuring D corrects those faults ;)I should also add that, in my opinion, any design where "const" means something other than "value resolved at compile time and immutable at runtime" would be a mistake.Then how would you call "value that's not mutable through this alias" in a way that's not going to turn C++ immigrants away?I think it's worthwhile ensuring D gets it right instead, and I'll happily change all of Tango to reflect that if necessary. Breaking source-code for a keyword that is currently used rarely is not a problem. Incorrect or dubious/confusing semantics are. It may be worthwhile dumping the "const" keyword altogether, to limit confusion.You know, that might be a good idea.BTW, you've also mentioned changing "inout" to "ref" instead? That would probably break more code than a renaming of const; I know both Tango and Mango use inout quite a bit, but I'm happy to change those as necessary. Other people likely feel the same way.Thanks, that's good to hear. Dropping inout would be one of the harder decisions to make. Andrei
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Benji Smith wrote:I have no special love (nor contempt, of course) for C++ immigrants and don't really care whether D conforms to their expectations. I thought the point of D was to fix broken constructs from C++, and most C++ programmers I know consider its implementation of const (and especially how casting affects const) to be one of the prime offenders. --benjiI should also add that, in my opinion, any design where "const" means something other than "value resolved at compile time and immutable at runtime" would be a mistake.Then how would you call "value that's not mutable through this alias" in a way that's not going to turn C++ immigrants away? Andrei
Mar 16 2007
On Fri, 16 Mar 2007 12:38:00 -0700, Benji Smith wrote:Andrei Alexandrescu (See Website For Email) wrote:Thank you Benji ... I've been trying to write a response to that but everything I wrote came out as too abusive or obnoxious. You have nailed it though. -- Derek Parnell Melbourne, Australia "Justice for David Hicks!" skype: derek.j.parnellBenji Smith wrote:I have no special love (nor contempt, of course) for C++ immigrants and don't really care whether D conforms to their expectations. I thought the point of D was to fix broken constructs from C++, and most C++ programmers I know consider its implementation of const (and especially how casting affects const) to be one of the prime offenders.I should also add that, in my opinion, any design where "const" means something other than "value resolved at compile time and immutable at runtime" would be a mistake.Then how would you call "value that's not mutable through this alias" in a way that's not going to turn C++ immigrants away? Andrei
Mar 16 2007
Benji Smith wrote:Andrei Alexandrescu (See Website For Email) wrote:Well, you see - quot capita, tot sententiae. :o) It's not about expectations as much as taking the good without the bad, while avoiding gratuitous incompatibilities. This is, I understand, high on Walter's priority list.Benji Smith wrote:I have no special love (nor contempt, of course) for C++ immigrants and don't really care whether D conforms to their expectations.I should also add that, in my opinion, any design where "const" means something other than "value resolved at compile time and immutable at runtime" would be a mistake.Then how would you call "value that's not mutable through this alias" in a way that's not going to turn C++ immigrants away? AndreiI thought the point of D was to fix broken constructs from C++, and most C++ programmers I know consider its implementation of const (and especially how casting affects const) to be one of the prime offenders.We know why C++ const is broken. The fact that it does not mean super const is not the reason. Andrei
Mar 16 2007
Benji Smith wrote:Andrei Alexandrescu (See Website For Email) wrote:Same opinion here. What makes D good is fixing broken constructs from C++. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DBenji Smith wrote:I have no special love (nor contempt, of course) for C++ immigrants and don't really care whether D conforms to their expectations. I thought the point of D was to fix broken constructs from C++, and most C++ programmers I know consider its implementation of const (and especially how casting affects const) to be one of the prime offenders. --benjiI should also add that, in my opinion, any design where "const" means something other than "value resolved at compile time and immutable at runtime" would be a mistake.Then how would you call "value that's not mutable through this alias" in a way that's not going to turn C++ immigrants away? Andrei
Mar 16 2007
Bruno Medeiros wrote:Benji Smith wrote:Same opinion here too. AndreiAndrei Alexandrescu (See Website For Email) wrote:Same opinion here. What makes D good is fixing broken constructs from C++.Benji Smith wrote:I have no special love (nor contempt, of course) for C++ immigrants and don't really care whether D conforms to their expectations. I thought the point of D was to fix broken constructs from C++, and most C++ programmers I know consider its implementation of const (and especially how casting affects const) to be one of the prime offenders. --benjiI should also add that, in my opinion, any design where "const" means something other than "value resolved at compile time and immutable at runtime" would be a mistake.Then how would you call "value that's not mutable through this alias" in a way that's not going to turn C++ immigrants away? Andrei
Mar 16 2007
Benji Smith wrote:I should also add that, in my opinion, any design where "const" means something other than "value resolved at compile time and immutable at runtime" would be a mistake.I hear you. I've always disliked C++'s mutable const. The most important thing at this stage is not the keyword, however, but getting the design right. Andrei, myself and Bartosz have been to hell and back several times over this over the last few months, and have filled about two notebooks with scribblings. It's a difficult problem. There are 3 distinct, and very different, flavors of constant: 1) rebinding of a value to a name 2) a read-only view of a data structure 3) a value that never changes C++ tries to do all three with one keyword, and makes a confusing hash of it. For the purposes of discussion, and to avoid confusing ourselves, we adopted working names of: 1) final 2) const 3) super const The hard part is to figure out how these 3 interact, how they look & feel, how they work with type deduction, type inference, type combining, how do we sidestep the clumsiness in C++'s handling of it, etc. Once that's all done, picking the right keywords is a whole 'nother discussion, with several considerations: 1) common use of 'const' in C++, and the expectations and comfort people coming from C++ have with it 2) your point above, that const should be constant 3) keyword minimization 4) avoid stepping on commonly used names 5) ease and economy of typing
Mar 16 2007
Walter Bright wrote:There are 3 distinct, and very different, flavors of constant: 1) rebinding of a value to a name 2) a read-only view of a data structure 3) a value that never changes C++ tries to do all three with one keyword, and makes a confusing hash of it. For the purposes of discussion, and to avoid confusing ourselves, we adopted working names of: 1) final 2) const 3) super constI appreciate the thought you guys have put into it. And the implementation sounds exactly right, from a semantic perspective. It's just the syntax that's slightly wrong, to me. Using your mapping above, I'd tweak it slightly to read: 1) final 2) readonly 3) const On a side note: if the existing proposal was enacted, I think the exclamation point would be the most commonly overloaded symbol (possibly only competing with * for multiplication, pointer declaration, and pointer dereferencing), while other symbols (like ^ or %) are currently only single-purpose. Any overriding philosophy on the usage and overloading of symbol characters? --benji
Mar 16 2007
Benji Smith wrote:Any overriding philosophy on the usage and overloading of symbol characters?Not that I can think of.
Mar 16 2007
Walter Bright wrote:Benji Smith wrote:Glad to hear you guys are open to considerations. For purpose of discussion, you /could/ adopt the following instead: 1) final - rebinding of a value to a name 2) view - a read-only view of a data structure 3) constant - a value that never changes Not only is that pretty clear, it also dumps the "const" keyword that may otherwise cause some "adjustment" for C++ peopleI should also add that, in my opinion, any design where "const" means something other than "value resolved at compile time and immutable at runtime" would be a mistake.I hear you. I've always disliked C++'s mutable const. The most important thing at this stage is not the keyword, however, but getting the design right. Andrei, myself and Bartosz have been to hell and back several times over this over the last few months, and have filled about two notebooks with scribblings. It's a difficult problem. There are 3 distinct, and very different, flavors of constant: 1) rebinding of a value to a name 2) a read-only view of a data structure 3) a value that never changes C++ tries to do all three with one keyword, and makes a confusing hash of it. For the purposes of discussion, and to avoid confusing ourselves, we adopted working names of: 1) final 2) const 3) super const The hard part is to figure out how these 3 interact, how they look & feel, how they work with type deduction, type inference, type combining, how do we sidestep the clumsiness in C++'s handling of it, etc. Once that's all done, picking the right keywords is a whole 'nother discussion, with several considerations: 1) common use of 'const' in C++, and the expectations and comfort people coming from C++ have with it 2) your point above, that const should be constant 3) keyword minimization 4) avoid stepping on commonly used names 5) ease and economy of typing
Mar 16 2007
Walter Bright wrote:Benji Smith wrote:I very much agree. But with little information about how these new flavors of const will work, it seems we're mostly stuck debating how they will look :-) I'd welcome discussing the former issue, but I suspect that anything which is said here will have already been discussed between you three.I should also add that, in my opinion, any design where "const" means something other than "value resolved at compile time and immutable at runtime" would be a mistake.I hear you. I've always disliked C++'s mutable const. The most important thing at this stage is not the keyword, however, but getting the design right. Andrei, myself and Bartosz have been to hell and back several times over this over the last few months, and have filled about two notebooks with scribblings. It's a difficult problem.There are 3 distinct, and very different, flavors of constant: 1) rebinding of a value to a name 2) a read-only view of a data structure 3) a value that never changesmeans pointers and class handles. Further, I don't think I've ever found a need for this particular class of immutability in C++. How often does it really matter whether someone can reassign a pointer? this much thought, but is it truly necessary to have two separate is there a perceived value here from a user perspective? Please don't get me wrong, I very much appreciate the desire for a comprehensive solution, but at the same time I wonder whether the struggle to integrate three fairly diverse concepts might be part of the reason why this all seems so complicated. Are they all truly necessary? And is it necessary to distinguish all three by separate keywords?C++ tries to do all three with one keyword, and makes a confusing hash of it.Agreed, despite how the above likely sounds. Sean
Mar 16 2007
Sean Kelly wrote:Walter Bright wrote:Benji Smith wrote:I very much agree. But with little information about how these new flavors of const will work, it seems we're mostly stuck debating how they will look :-) I'd welcome discussing the former issue, but I suspect that anything which is said here will have already been discussed between you three.I should also add that, in my opinion, any design where "const" means something other than "value resolved at compile time and immutable at runtime" would be a mistake.I hear you. I've always disliked C++'s mutable const. The most important thing at this stage is not the keyword, however, but getting the design right. Andrei, myself and Bartosz have been to hell and back several times over this over the last few months, and have filled about two notebooks with scribblings. It's a difficult problem.There are 3 distinct, and very different, flavors of constant: 1) rebinding of a value to a name 2) a read-only view of a data structure 3) a value that never changesmeans pointers and class handles.Further, I don't think I've ever found a need for this particular class of immutability in C++. How often does it really matter whether someone can reassign a pointer?Very important. Often you want to bind a pointer to something and make sure nothing can change that.No, because the value may embed pointers that you want to pass to functions. Sorry for sounding dismissive, but we've been all of these dead alleys for so long, it's all green codes: I can see the damn Matrix now. Blonde, brunette, const, final...const. Essentially "const" loses a little of the precision that "super const" has.I haven't given this much thought, but is it truly necessary to have two separateIt's not! That's what I tried to do all along...Is this to aid the compiler in optimizing, or is there a perceived value here from a user perspective?It will be absolutely essential for the well-definedness of functional-style threads.Please don't get me wrong, I very much appreciate the desire for a comprehensive solution, but at the same time I wonder whether the struggle to integrate three fairly diverse concepts might be part of the reason why this all seems so complicated. Are they all truly necessary?I'd think so.And is it necessary to distinguish all three by separate keywords?It's not necessary :o). Andrei
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Sean Kelly wrote:Could you please provide an example?Walter Bright wrote:Benji Smith wrote:I very much agree. But with little information about how these new flavors of const will work, it seems we're mostly stuck debating how they will look :-) I'd welcome discussing the former issue, but I suspect that anything which is said here will have already been discussed between you three.I should also add that, in my opinion, any design where "const" means something other than "value resolved at compile time and immutable at runtime" would be a mistake.I hear you. I've always disliked C++'s mutable const. The most important thing at this stage is not the keyword, however, but getting the design right. Andrei, myself and Bartosz have been to hell and back several times over this over the last few months, and have filled about two notebooks with scribblings. It's a difficult problem.There are 3 distinct, and very different, flavors of constant: 1) rebinding of a value to a name 2) a read-only view of a data structure 3) a value that never changesmeans pointers and class handles.Perhaps this should be rewritten as "often one wants to..." I just said that I have never felt a need for this :-) Of the times where I've used this feature in C/C++, I think every single time has been simply out of diligence rather than because there was any risk of the pointer actually being reassigned. A pertinent point to me is that D uses pass-by-value so the chance of a reference being silently reassigned "somewhere in the program" is typically almost nil. About the only place where this is a real risk is with global variables, and since free functions support the property syntax, the programmer has a ready option to prevent such a reassignment from happening. Besides, free globals are bad programming style anyway.Further, I don't think I've ever found a need for this particular class of immutability in C++. How often does it really matter whether someone can reassign a pointer?Very important. Often you want to bind a pointer to something and make sure nothing can change that.That's fine. You may have been down all these roads before, but I haven't. I'm mostly asking to gain a better understanding of some of the background.No, because the value may embed pointers that you want to pass to functions. Sorry for sounding dismissive, but we've been all of these dead alleys for so long, it's all green codes: I can see the damn Matrix now. Blonde, brunette, const, final...const. Essentially "const" loses a little of the precision that "super const" has.(see below)I haven't given this much thought, but is it truly necessary to haveIt's not! That's what I tried to do all along...Okay, that's what I figured, though this seems to contradict what you said above. So in essence, "super const" is actually necessary in some situations to indicate to the programmer that the data he is manipulating is truly immutable. I almost feel like this feature should exist separately from the type mechanism, so there was a way to test for this instead.Is this to aid the compiler in optimizing, or is there a perceived value here from a user perspective?It will be absolutely essential for the well-definedness of functional-style threads.for both, but I very much do not want all of this to become a confusing mess when applied to actual code. SeanAnd is it necessary to distinguish all three by separate keywords?It's not necessary :o).
Mar 16 2007
Sean Kelly wrote:Andrei Alexandrescu (See Website For Email) wrote:final int x = 42;Sean Kelly wrote:Could you please provide an example?Walter Bright wrote:Benji Smith wrote:I very much agree. But with little information about how these new flavors of const will work, it seems we're mostly stuck debating how they will look :-) I'd welcome discussing the former issue, but I suspect that anything which is said here will have already been discussed between you three.I should also add that, in my opinion, any design where "const" means something other than "value resolved at compile time and immutable at runtime" would be a mistake.I hear you. I've always disliked C++'s mutable const. The most important thing at this stage is not the keyword, however, but getting the design right. Andrei, myself and Bartosz have been to hell and back several times over this over the last few months, and have filled about two notebooks with scribblings. It's a difficult problem.There are 3 distinct, and very different, flavors of constant: 1) rebinding of a value to a name 2) a read-only view of a data structure 3) a value that never changesmeans pointers and class handles.I think "final" is mostly useful in class and struct members.Perhaps this should be rewritten as "often one wants to..." I just said that I have never felt a need for this :-) Of the times where I've used this feature in C/C++, I think every single time has been simply out of diligence rather than because there was any risk of the pointer actually being reassigned. A pertinent point to me is that D uses pass-by-value so the chance of a reference being silently reassigned "somewhere in the program" is typically almost nil. About the only place where this is a real risk is with global variables, and since free functions support the property syntax, the programmer has a ready option to prevent such a reassignment from happening. Besides, free globals are bad programming style anyway.Further, I don't think I've ever found a need for this particular class of immutability in C++. How often does it really matter whether someone can reassign a pointer?Very important. Often you want to bind a pointer to something and make sure nothing can change that.That's fine. You may have been down all these roads before, but I haven't. I'm mostly asking to gain a better understanding of some of the background.No, because the value may embed pointers that you want to pass to functions. Sorry for sounding dismissive, but we've been all of these dead alleys for so long, it's all green codes: I can see the damn Matrix now. Blonde, brunette, const, final...const. Essentially "const" loses a little of the precision that "super const" has.Then you can't prove correctness statically.(see below)I haven't given this much thought, but is it truly necessary to haveIt's not! That's what I tried to do all along...Okay, that's what I figured, though this seems to contradict what you said above. So in essence, "super const" is actually necessary in some situations to indicate to the programmer that the data he is manipulating is truly immutable. I almost feel like this feature should exist separately from the type mechanism, so there was a way to test for this instead.Is this to aid the compiler in optimizing, or is there a perceived value here from a user perspective?It will be absolutely essential for the well-definedness of functional-style threads.Much anything else would become a mess when applied to actual code. I think we discussed about two dozens of schemes. They all looked great on paper, at least at first blush. They all did miserably during a test drive. Andreifor both, but I very much do not want all of this to become a confusing mess when applied to actual code.And is it necessary to distinguish all three by separate keywords?It's not necessary :o).
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Sean Kelly wrote:I must be missing something here. I expected this to be the point of 'const'. In C++ parlance: int const * const val = 0; ^ ^ | |Andrei Alexandrescu (See Website For Email) wrote:final int x = 42;Sean Kelly wrote:Could you please provide an example?Walter Bright wrote:There are 3 distinct, and very different, flavors of constant: 1) rebinding of a value to a name 2) a read-only view of a data structure 3) a value that never changesmeans pointers and class handles.I think "final" is mostly useful in class and struct members.Seems reasonable I suppose. Will there be any change to "final" as it exists now in D, or is this simply an extension of its meaning?Argh. Good point.Okay, that's what I figured, though this seems to contradict what you said above. So in essence, "super const" is actually necessary in some situations to indicate to the programmer that the data he is manipulating is truly immutable. I almost feel like this feature should exist separately from the type mechanism, so there was a way to test for this instead.Then you can't prove correctness statically.Well... darnit :-) SeanSo it sounds like it truly isn't necessary to separately distinguish need for both, but I very much do not want all of this to become a confusing mess when applied to actual code.Much anything else would become a mess when applied to actual code. I think we discussed about two dozens of schemes. They all looked great on paper, at least at first blush. They all did miserably during a test drive.
Mar 16 2007
Walter Bright wrote:For the purposes of discussion, and to avoid confusing ourselves, we adopted working names of: 1) final 2) const 3) super constHow about taking Andrei's observation about extern(C) and scope(exit) and letting const have a modifier? 1) final 2) const 3) const(strong) or something like that? I guess the problem is that const(something) already has a meaning if it's something like const(int*). --bb
Mar 16 2007
Walter Bright wrote:There are 3 distinct, and very different, flavors of constant: 1) rebinding of a value to a name 2) a read-only view of a data structure 3) a value that never changes C++ tries to do all three with one keyword, and makes a confusing hash of it. For the purposes of discussion, and to avoid confusing ourselves, we adopted working names of: 1) final 2) const 3) super constWell, I'm a C++ programmer and I think the last two are much more confusing than "readonly" and a different "const". If they keywords are simple and intuitive then the learning curve will be quick. Can't get much better than "readonly" (I can't write to this data, but it may change) and "const" (the data will not change). Consider these two statements: The problem with C++ "const" is that it isn't really constant. D fixes this by having "readonly" for an immutable view, and "const" actually meaning that the data is guaranteed not going to change. The problem with C++ "const" is that it isn't really constant. D's "const" is also not really constant, but "super const" has been added for data that is guaranteed not going to change. Also, I am slightly confused why examples of final have been given with value types: final int x = 3; But x can never be rebound as it isn't a reference - what the user really means is the value never changes, therefore keyword (3) rather than keyword (1) seems appropriate here.The hard part is to figure out how these 3 interact, how they look & feel, how they work with type deduction, type inference, type combining, how do we sidestep the clumsiness in C++'s handling of it, etc.Regardless of syntax, I would love to hear the advantages of the proposed system. It seems the really big change is the addition of (3), but I can't quite see how you could create complex data sets that are guaranteed constant apart from using "trust me" casts. For example, an function may take a data set as super const, therefore making optimisations. But the creation of such a data set (say a map of ints to an array of strings, or a graph of nodes) may well be done at runtime, such as loading it from a file. How do you "pin" runtime data to get a super constant type? Can you even create super const data using custom classes? Must everything be done in the constructor? What about pointers to non-owned non-constant data, such as back to an owner object? I'm intrigued. Any chance of posting some "behind the scenes" with the discussion and resolution to the issues you guys have grappled with?
Mar 17 2007
Benji Smith wrote:Andrei Alexandrescu (See Website For Email) wrote:No. super const deals with pointers and transitivity. Final deals with non-rebindable symbols. I'd be hard pressed to think of many examples where class members are transitively immutable.We've shoved keywords like "readonly" and "view" for a while, and they just added more confusion than cleared, at a high cost. If (as I suspect) super const appears relatively infrequently, it might be fine to just encode it as the mildly verbose "super const". In fact, it's shorter than "keepyourgrubbyhandsoff". :o) AndreiReally? I'd think super const would be used all the time. Anywhere a class has some invariant field, it'll probably be expressed as super const (if I'm understanding correctly that super const is the equivalent of #define constants in C++ or static final constants in Java).Let me join the ranks of those who hate both versions of the new syntax. const! looks either like a template or like "not const". You guys may think you're saving a keyword, and that might be technically correct from the perspective of the parser.The parser has zilch to do with it.But, for the perspective of the D developer, it still looks like you've introduced a new keyword, but it's a keyword that's A) nearly identical to another keyword, and B) contains a symbol. Ugh. I really. Really. Really. Hate it.Can't help. For any given feature, there will be people who hate it. Usually they are also the most vocal :o).Using "super const" is also annoying because all of the other storage classes use a single keyword. Now we've got this weird case that uses two keywords. And the word "super" is now overloaded in two completely unrelated concepts.So what? Don't we use words in natural language that are polysemous too? As long as the context makes it unambiguous, great.(By the way, I don't like "static if" either. I think the right choice would have been #if, #foreach, etc. And I think C++ made a mistake by defining "long long" and "double double" types as well. Presumably, that saved some keywords, but we'd all have been better off if the types were defined as int8, int16, int32, int64, float32, float64, etc).You're making my point exactly. I love static if, and don't like #if. Again: for each feature, there will be people who like it and hate it :o).I vote for "readonly" and "const". Anything else seems like a mistake.Which is which? How would you have people distinguish them without running to the manual? How would you explain C++ immigrants that const is actually readonly, and there is a const, but that const means something else than their const? Andrei
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Benji Smith wrote:How would you have people distinguish char/wchar/dchar without running to the Unicode standard to see which characters they can hold in a single unit? Or short/int/long or float/double/real without running to the standard to look up the ranges and precision of those data types? How would you explain to the average person from the Netherlands/Estonia/Finland/Germany/Slovakia[1] 'auto' doesn't have anything to do with transportation? How would you explain to Dutchmen that 'long' doesn't have anything to do with breathing air? (Hint for all you foreigners out here: the Dutch word 'long' translates to 'lung' :P ) Some things are somewhat arbitrary conventions. When you learn a new language, some words will mean different things, with other words that have the meaning you're used to. It happens ;). [1]: See http://dictionary.reference.com/search?q=car , specifically the first set of translations, roughly halfway down the page Seriously though: "readonly" would mean that you (meaning any code that can access the symbol so declared) can only read data referenced through it, but someone else _may_ be able to write to it[2]. "const" would mean it's just that: constant. *Nobody* can write to it. Seems pretty easy to explain to me. The only caveat I see is that "readonly" would mean the object itself can still be modified, as opposed to final. I don't see how calling it "const" would fix that, though. [2]: Or of course that same code may be able to write to it, if for whatever reason it also has access to a mutable reference to the same data.I vote for "readonly" and "const". Anything else seems like a mistake.Which is which? How would you have people distinguish them without running to the manual? How would you explain C++ immigrants that const is actually readonly, and there is a const, but that const means something else than their const?
Mar 16 2007
Frits van Bommel wrote:Seriously though: "readonly" would mean that you (meaning any code that can access the symbol so declared) can only read data referenced through it, but someone else _may_ be able to write to it[2].My perception of that is different. I used to do embedded systems, and 'readonly' means the data went into ROM. Also, marking a page in a virtual memory system as 'readonly' means that nobody can modify it. 'super const' at least has the connotation of being "constant, this time we mean it".
Mar 16 2007
Walter Bright wrote:Frits van Bommel wrote:Perhaps, but my perception of 'const' is different ;). Particularly, it seems to be short for "constant", which is therefore what it should mean. Not "*you* can't change this, but someone else might anyway". Oh, and on x86 (and amd64) processors the operating system is allowed to write to 'readonly'[1] pages unless it sets the WP (Write-Protect) bit in system register CR0. Note: as this bit is *off* by default, it needs to be explicitly turned on by the OS. [1] Well, technically they're not really readonly, it's more like non-writable (since the appropriate bit must be 1 on all levels of the paging data structures to get a writable page) but that's heading /even faster/ into the realm of nitpicking :).Seriously though: "readonly" would mean that you (meaning any code that can access the symbol so declared) can only read data referenced through it, but someone else _may_ be able to write to it[2].My perception of that is different. I used to do embedded systems, and 'readonly' means the data went into ROM. Also, marking a page in a virtual memory system as 'readonly' means that nobody can modify it.'super const' at least has the connotation of being "constant, this time we mean it".Wouldn't it be better if 'const' just _meant what it said_ in the first place? :P
Mar 16 2007
Frits van Bommel wrote:Walter Bright wrote:So *that's* why Win32 doesn't complain when constant data is modified and pretty much every other OS does. Good to know. By the way... I feel the same about the meaning of 'const'. On some level I still even think that const-by-default is the correct choice, but now that D has hit 1.0 that will be a much harder sell. SeanFrits van Bommel wrote:Perhaps, but my perception of 'const' is different ;). Particularly, it seems to be short for "constant", which is therefore what it should mean. Not "*you* can't change this, but someone else might anyway". Oh, and on x86 (and amd64) processors the operating system is allowed to write to 'readonly'[1] pages unless it sets the WP (Write-Protect) bit in system register CR0. Note: as this bit is *off* by default, it needs to be explicitly turned on by the OS.Seriously though: "readonly" would mean that you (meaning any code that can access the symbol so declared) can only read data referenced through it, but someone else _may_ be able to write to it[2].My perception of that is different. I used to do embedded systems, and 'readonly' means the data went into ROM. Also, marking a page in a virtual memory system as 'readonly' means that nobody can modify it.
Mar 16 2007
Sean Kelly wrote:Frits van Bommel wrote:[snip]Walter Bright wrote:[snip]'readonly' means the data went into ROM. Also, marking a page in a virtual memory system as 'readonly' means that nobody can modify it.No I don't think so. The 'WP' bit only applies to kernel-level (ring 0-2) code. Ring 3 code (i.e. normal user-level code) can never write into "readonly" pages. The only explanation I can think of for Win32 allowing writes into a programs read-only data is that the pages aren't marked "readonly" at all for some reason. Unless of course user-level code is ran somewhere in ring 0-2, but I don't think even Windows would do something so stupidly insecure: that would allow user-level code to read and write anywhere in kernel space, barring segment limits. (I didn't say Microsoft instead of Windows above, since Microsoft's research division is experimenting with a .NET based OS that *does* run everything in ring 0. However, that uses a different mechanism to ensure safety: programs are checked for type-safety before being allowed to run. That's not really feasible for traditional machine-code based OSs though...)Oh, and on x86 (and amd64) processors the operating system is allowed to write to 'readonly'[1] pages unless it sets the WP (Write-Protect) bit in system register CR0. Note: as this bit is *off* by default, it needs to be explicitly turned on by the OS.So *that's* why Win32 doesn't complain when constant data is modified and pretty much every other OS does. Good to know.
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Benji Smith wrote:Hospitality to C++ immigrants is definitely important. But since C++ const is broken, there's inevitably going to be some culture shock. I think we're OK as long as D const is more restrictive than C++ const -- so that writing C++ code in D will either work the same as in C++, or fail to compile. And I don't think that the confusion exists for anyone other than C++ programmers. DonI vote for "readonly" and "const". Anything else seems like a mistake.Which is which? How would you have people distinguish them without running to the manual? How would you explain C++ immigrants that const is actually readonly, and there is a const, but that const means something else than their const?
Mar 16 2007
Don Clugston wrote:Andrei Alexandrescu (See Website For Email) wrote:Let me say it again: we know why it's broken. We will provide a fixed equivalent, not something entirely different. It's only natural to call the fixed equivalent the same.Benji Smith wrote:Hospitality to C++ immigrants is definitely important. But since C++ const is broken, there's inevitably going to be some culture shock.I vote for "readonly" and "const". Anything else seems like a mistake.Which is which? How would you have people distinguish them without running to the manual? How would you explain C++ immigrants that const is actually readonly, and there is a const, but that const means something else than their const?I think we're OK as long as D const is more restrictive than C++ const -- so that writing C++ code in D will either work the same as in C++, or fail to compile. And I don't think that the confusion exists for anyone other than C++ programmers.Which are in the millions :o). Andrei
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Aha. In that case, what would you think of the declaration: super const int MY_CONSTANT = 6; Since a value type doesn't have any pointers, it wouldn't make any sense to apply super-constness to it, right? Should that be a compiler error? --benjiReally? I'd think super const would be used all the time. Anywhere a class has some invariant field, it'll probably be expressed as super const (if I'm understanding correctly that super const is the equivalent of #define constants in C++ or static final constants in Java).No. super const deals with pointers and transitivity. Final deals with non-rebindable symbols. I'd be hard pressed to think of many examples where class members are transitively immutable.
Mar 16 2007
Benji Smith wrote:Andrei Alexandrescu (See Website For Email) wrote:This should be a compiler error. AndreiAha. In that case, what would you think of the declaration: super const int MY_CONSTANT = 6; Since a value type doesn't have any pointers, it wouldn't make any sense to apply super-constness to it, right? Should that be a compiler error?Really? I'd think super const would be used all the time. Anywhere a class has some invariant field, it'll probably be expressed as super const (if I'm understanding correctly that super const is the equivalent of #define constants in C++ or static final constants in Java).No. super const deals with pointers and transitivity. Final deals with non-rebindable symbols. I'd be hard pressed to think of many examples where class members are transitively immutable.
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Benji Smith wrote:Cool. That's what I'd expect. Maybe rather than "super const", you could use "ref const" or "const*" or something that directly indicates that this form of constantness applies to the pointers rather than the values. If you use "ref" as a replacement for "inout", then the "ref" keyword would get some re-use. Actually, though, I kind of like the idea of "const*" // Create a constant pointer from a mutable pointer const* int* myPointer = pMutableInt; // Or maybe like this: *const int* myPointer = pMutableInt; What do you think of that? At least the asterisk provides a better clue to the functionality of the construct than an exclamation point would. --benjiAha. In that case, what would you think of the declaration: super const int MY_CONSTANT = 6; Since a value type doesn't have any pointers, it wouldn't make any sense to apply super-constness to it, right? Should that be a compiler error?This should be a compiler error. Andrei
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Benji Smith wrote:Well this explains a lot. I'd misunderstood as well. SeanAndrei Alexandrescu (See Website For Email) wrote:No. super const deals with pointers and transitivity. Final deals with non-rebindable symbols. I'd be hard pressed to think of many examples where class members are transitively immutable.We've shoved keywords like "readonly" and "view" for a while, and they just added more confusion than cleared, at a high cost. If (as I suspect) super const appears relatively infrequently, it might be fine to just encode it as the mildly verbose "super const". In fact, it's shorter than "keepyourgrubbyhandsoff". :o)Really? I'd think super const would be used all the time. Anywhere a class has some invariant field, it'll probably be expressed as super const (if I'm understanding correctly that super const is the equivalent of #define constants in C++ or static final constants in Java).
Mar 16 2007
On Fri, 16 Mar 2007 09:55:15 -0700, Benji Smith wrote:Andrei Alexandrescu (See Website For Email) wrote:Well expressed. My think is almost 100% aligned with these thoughts above. -- Derek Parnell Melbourne, Australia "Justice for David Hicks!" skype: derek.j.parnellWe've shoved keywords like "readonly" and "view" for a while, and they just added more confusion than cleared, at a high cost. If (as I suspect) super const appears relatively infrequently, it might be fine to just encode it as the mildly verbose "super const". In fact, it's shorter than "keepyourgrubbyhandsoff". :o) AndreiReally? I'd think super const would be used all the time. Anywhere a class has some invariant field, it'll probably be expressed as super const (if I'm understanding correctly that super const is the equivalent of #define constants in C++ or static final constants in Java). Let me join the ranks of those who hate both versions of the new syntax. const! looks either like a template or like "not const". You guys may think you're saving a keyword, and that might be technically correct from the perspective of the parser. But, for the perspective of the D developer, it still looks like you've introduced a new keyword, but it's a keyword that's A) nearly identical to another keyword, and B) contains a symbol. Ugh. I really. Really. Really. Hate it. Using "super const" is also annoying because all of the other storage classes use a single keyword. Now we've got this weird case that uses two keywords. And the word "super" is now overloaded in two completely unrelated concepts. (By the way, I don't like "static if" either. I think the right choice would have been #if, #foreach, etc. And I think C++ made a mistake by defining "long long" and "double double" types as well. Presumably, that saved some keywords, but we'd all have been better off if the types were defined as int8, int16, int32, int64, float32, float64, etc). I vote for "readonly" and "const". Anything else seems like a mistake. --benji
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:We've shoved keywords like "readonly" and "view" for a while, and they just added more confusion than cleared, at a high cost. If (as I suspect) super const appears relatively infrequently, it might be fine to just encode it as the mildly verbose "super const". In fact, it's shorter than "keepyourgrubbyhandsoff". :o)How about “const const”? No new keywords, no reuse of keywords in disparate contexts, and equally noticeable to the eye. --Joel
Mar 16 2007
How about “const const”? No new keywords, no reuse of keywords in disparate contexts, and equally noticeable to the eye. --JoelNoticeable alright! I can't even type those characters. : D
Mar 16 2007
Joel C. Salomon wrote:Andrei Alexandrescu (See Website For Email) wrote:The whole things about adding *more* constantness to const screams one thing very loudly: the applicability of the word "const", in this context, is borked :)We've shoved keywords like "readonly" and "view" for a while, and they just added more confusion than cleared, at a high cost. If (as I suspect) super const appears relatively infrequently, it might be fine to just encode it as the mildly verbose "super const". In fact, it's shorter than "keepyourgrubbyhandsoff". :o)How about “const const”? No new keywords, no reuse of keywords in disparate contexts, and equally noticeable to the eye. --Joel
Mar 16 2007
kris wrote:Joel C. Salomon wrote:Bingo. It's like trying to describe something as "impossible impossible". If the first usage of the word didn't really convey impossibility, then you were using the wrong word to begin with. --bAndrei Alexandrescu (See Website For Email) wrote:The whole things about adding *more* constantness to const screams one thing very loudly: the applicability of the word "const", in this context, is borked :)We've shoved keywords like "readonly" and "view" for a while, and they just added more confusion than cleared, at a high cost. If (as I suspect) super const appears relatively infrequently, it might be fine to just encode it as the mildly verbose "super const". In fact, it's shorter than "keepyourgrubbyhandsoff". :o)How about “const const”? No new keywords, no reuse of keywords in disparate contexts, and equally noticeable to the eye. --Joel
Mar 16 2007
Benji Smith wrote:kris wrote:You're "dead dead" right! :o) AndreiJoel C. Salomon wrote:Bingo. It's like trying to describe something as "impossible impossible". If the first usage of the word didn't really convey impossibility, then you were using the wrong word to begin with.Andrei Alexandrescu (See Website For Email) wrote:The whole things about adding *more* constantness to const screams one thing very loudly: the applicability of the word "const", in this context, is borked :)We've shoved keywords like "readonly" and "view" for a while, and they just added more confusion than cleared, at a high cost. If (as I suspect) super const appears relatively infrequently, it might be fine to just encode it as the mildly verbose "super const". In fact, it's shorter than "keepyourgrubbyhandsoff". :o)How about “const const”? No new keywords, no reuse of keywords in disparate contexts, and equally noticeable to the eye. --Joel
Mar 16 2007
On Fri, 16 Mar 2007 14:25:36 -0700, Andrei Alexandrescu (See Website For Email) wrote:Reminds me a bit of the joke ... Teacher: Two negatives imply a positive ... eg. 'not bad' is 'good'. But two positives never imply a negative. Student: Yeah ... right, whatever. -- Derek Parnell Melbourne, Australia "Justice for David Hicks!" skype: derek.j.parnellBingo. It's like trying to describe something as "impossible impossible". If the first usage of the word didn't really convey impossibility, then you were using the wrong word to begin with.You're "dead dead" right! :o)
Mar 16 2007
Benji Smith wrote:Bingo. It's like trying to describe something as "impossible impossible". If the first usage of the word didn't really convey impossibility, then you were using the wrong word to begin with.Reminds me of the old assembler program: foo: MOV EAX, 3 CALL BAR HALT ; stop the program HALT ; if skidding
Mar 16 2007
Walter Bright wrote:Benji Smith wrote:LOLBingo. It's like trying to describe something as "impossible impossible". If the first usage of the word didn't really convey impossibility, then you were using the wrong word to begin with.Reminds me of the old assembler program: foo: MOV EAX, 3 CALL BAR HALT ; stop the program HALT ; if skidding
Mar 16 2007
kris wrote:Walter Bright wrote:You know those teenagers with the overclocked CPUs...Benji Smith wrote:LOLBingo. It's like trying to describe something as "impossible impossible". If the first usage of the word didn't really convey impossibility, then you were using the wrong word to begin with.Reminds me of the old assembler program: foo: MOV EAX, 3 CALL BAR HALT ; stop the program HALT ; if skidding
Mar 16 2007
Walter Bright wrote:Benji Smith wrote:LOLBingo. It's like trying to describe something as "impossible impossible". If the first usage of the word didn't really convey impossibility, then you were using the wrong word to begin with.Reminds me of the old assembler program: foo: MOV EAX, 3 CALL BAR HALT ; stop the program HALT ; if skidding
Mar 16 2007
Joel C. Salomon wrote:Andrei Alexandrescu (See Website For Email) wrote:It was on the plate briefly. Probably it would be an uphill battle to convince people to enjoy it. AndreiWe've shoved keywords like "readonly" and "view" for a while, and they just added more confusion than cleared, at a high cost. If (as I suspect) super const appears relatively infrequently, it might be fine to just encode it as the mildly verbose "super const". In fact, it's shorter than "keepyourgrubbyhandsoff". :o)How about “const const”? No new keywords, no reuse of keywords in disparate contexts, and equally noticeable to the eye.
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:I’m still kinda shaky on the question of why the various extra specifiers are needed. If a variable is being declared “const” ought to mean nobody can change it, if it’s a function parameter it’s a promise that the function won’t change it. How vital is it that the language express “put this in read-only memory” as opposed to “don’t put this in read-only memory, but complain if I try to change it”? Why should a function care if it got a pointer to read-only memory or if it just promised not to alter the value? For numeric constants that don’t need addresses, I’d suggest “define” rather than “final”, as in: define float PI = 3.14159; If the “#if” syntax for “static if” is adopted, I might even suggest “#define”, just to make it clear that something is happening at compile-time rather than run-time. --JoelHow about “const const”? No new keywords, no reuse of keywords in disparate contexts, and equally noticeable to the eye.It was on the plate briefly. Probably it would be an uphill battle to convince people to enjoy it.
Mar 17 2007
Andrei Alexandrescu (See Website For Email) wrote:Bruno Medeiros wrote:Thanks for the update: BTW: const!(char[]) Looks to much like a template to me, I'd imagine some syntax phasers would have a harder time then necessary. -JoelWhat is the status of the experimental designs for the "storage classes" manipulation that Andrei and others where thinking of for D. The last I heard from it was Andrei's max suggestion from his max design challenge, however, I think that suggestion may suffer from some problems in regards to the "maxtype" requirement, plus it is wholly incomplete in regards to how storage classes interact between each other. Like Andrei said, what is a "const inout lazy const char[]", if valid at all? Is there any news here? Is there a working(aka complete) design?We have talked about a design. In short, the intent is to define three flavors of immutability: a) final - a simple storage class controlling the immutability of the bits allocated for the symbol per se; b) const - type qualifier meaning an immutable view of an otherwise modifiable data. const does not control the bits of the object, only the storage addressed indirectly by it (transitively); c) "superconst" - denoted as "const!" or "super const": type qualifier meaning that the data is genuinely unmodifiable. There is talk about deprecating lazy if it's best implemented via other mechanisms. There is also talk about deprecating "inout" in favor of "ref" on grounds that the often-useful "inout const" is likely to become To read a declaration like "const inout lazy const char[]", you can first parenthesize it appropriately: const(inout(lazy(const(char[])))) The lazy thing is really a delegate that returns a const char[]. The inout around it passes that delegate by reference, and the const at the top makes the delegate immutable. Andrei
Mar 16 2007
janderson wrote:BTW: const!(char[]) Looks to much like a template to me, I'd imagine some syntax phasers would have a harder time then necessary.If you mean parsers, I don't think that'll be much of a problem. 'const' is a keyword, template names are not. If you use a syntax-highlighting reader you'll also see the difference between const!(char[]) and foo!(char[]) immediately, for the same reason. (This is not to be construed as support for the "const!" syntax. I just dislike for different reasons ;) )
Mar 16 2007
janderson wrote:Andrei Alexandrescu (See Website For Email) wrote:The damndest thing is that const! (as well as const) _is_ a template: it's a type constructor that takes another type as an argument and returns a type. AndreiBruno Medeiros wrote:Thanks for the update: BTW: const!(char[]) Looks to much like a template to me, I'd imagine some syntax phasers would have a harder time then necessary.What is the status of the experimental designs for the "storage classes" manipulation that Andrei and others where thinking of for D. The last I heard from it was Andrei's max suggestion from his max design challenge, however, I think that suggestion may suffer from some problems in regards to the "maxtype" requirement, plus it is wholly incomplete in regards to how storage classes interact between each other. Like Andrei said, what is a "const inout lazy const char[]", if valid at all? Is there any news here? Is there a working(aka complete) design?We have talked about a design. In short, the intent is to define three flavors of immutability: a) final - a simple storage class controlling the immutability of the bits allocated for the symbol per se; b) const - type qualifier meaning an immutable view of an otherwise modifiable data. const does not control the bits of the object, only the storage addressed indirectly by it (transitively); c) "superconst" - denoted as "const!" or "super const": type qualifier meaning that the data is genuinely unmodifiable. There is talk about deprecating lazy if it's best implemented via other mechanisms. There is also talk about deprecating "inout" in favor of "ref" on grounds that the often-useful "inout const" is To read a declaration like "const inout lazy const char[]", you can first parenthesize it appropriately: const(inout(lazy(const(char[])))) The lazy thing is really a delegate that returns a const char[]. The inout around it passes that delegate by reference, and the const at the top makes the delegate immutable. Andrei
Mar 16 2007
On Fri, 16 Mar 2007 00:16:48 +0300, Andrei Alexandrescu (See Website For= = Email) <SeeWebsiteForEmail erdani.org> wrote:a) final - a simple storage class controlling the immutability of the ==bits allocated for the symbol per se; b) const - type qualifier meaning an immutable view of an otherwise =modifiable data. const does not control the bits of the object, only t=he =storage addressed indirectly by it (transitively); c) "superconst" - denoted as "const!" or "super const": type qualifier==meaning that the data is genuinely unmodifiable.Great! What about the influence of this storage classes on class method's = signatures? Is this will be in D: class Data { ... } class Container { // non-const access to data. Data data() { ... } // const access to data. const Data data() const { ... } } void useContainer( const Container c ) { auto d =3D c.data(); // the type of d is 'const Data'. ... } ? -- = Regards, Yauheni Akhotnikau
Mar 16 2007
eao197 wrote:On Fri, 16 Mar 2007 00:16:48 +0300, Andrei Alexandrescu (See Website For Email) <SeeWebsiteForEmail erdani.org> wrote:Yes, that's part of the plan. Moreover, you'll likely have the ability to define const-transporting methods (methods that look identical but only need to pass the const of the object out to the return value) only once. This has been a source of annoyance in certain C++ idioms. Andreia) final - a simple storage class controlling the immutability of the bits allocated for the symbol per se; b) const - type qualifier meaning an immutable view of an otherwise modifiable data. const does not control the bits of the object, only the storage addressed indirectly by it (transitively); c) "superconst" - denoted as "const!" or "super const": type qualifier meaning that the data is genuinely unmodifiable.Great! What about the influence of this storage classes on class method's signatures? Is this will be in D: class Data { ... } class Container { // non-const access to data. Data data() { ... } // const access to data. const Data data() const { ... } } void useContainer( const Container c ) { auto d = c.data(); // the type of d is 'const Data'. ... } ?
Mar 16 2007
On Fri, 16 Mar 2007 12:43:19 +0300, Andrei Alexandrescu (See Website For Email) <SeeWebsiteForEmail erdani.org> wrote:Yes, that's part of the plan. Moreover, you'll likely have the ability to define const-transporting methods (methods that look identical but only need to pass the const of the object out to the return value) only once. This has been a source of annoyance in certain C++ idioms.Thanks, I'm glad to hear that! It seems that D with this storage classes and const-transporting methods will be almost different D, may be D 2.0 :) -- Regards, Yauheni Akhotnikau
Mar 16 2007
eao197 wrote:On Fri, 16 Mar 2007 12:43:19 +0300, Andrei Alexandrescu (See Website For Email) <SeeWebsiteForEmail erdani.org> wrote:Actually, this is exactly true. D 2.0. AndreiYes, that's part of the plan. Moreover, you'll likely have the ability to define const-transporting methods (methods that look identical but only need to pass the const of the object out to the return value) only once. This has been a source of annoyance in certain C++ idioms.Thanks, I'm glad to hear that! It seems that D with this storage classes and const-transporting methods will be almost different D, may be D 2.0 :)
Mar 16 2007
eao197 wrote:It seems that D with this storage classes and const-transporting methods will be almost different D, may be D 2.0 :)Or perhaps it should be called D++ ? --anders
Mar 16 2007
On Fri, 16 Mar 2007 15:12:09 +0300, Anders F Björklund <afb algonet.se> wrote:No, at first there must be 'D with macros' (like 'C with classes') and only then -- D++ :)) -- Regards, Yauheni AkhotnikauIt seems that D with this storage classes and const-transporting methods will be almost different D, may be D 2.0 :)Or perhaps it should be called D++ ?
Mar 16 2007
No, at first there must be 'D with macros' (like 'C with classes') and only then -- D++ :))*shudder* D already has templates. it shouldn't have a separate macro language. Having one indicates that the language itself somehow fails. Templates *should* be sufficient. Using the ++ notation for the language is dangerous. It allows you to only upgrade once. You can't have a D, D++, D 2.0 etc, it just doesn't fit, 'causing the language to completely stagnate. Then someone else has to come along and invent a language E. I think if we properly use 'const' to define something as 'not moving', and 'final' to define something as being 'unchangeable' then you can declare final const x and be done with it. The simpler the language is, the better. Sincerely, Dan
Mar 16 2007
Dan wrote:I think if we properly use 'const' to define something as 'not moving', and 'final' to define something as being 'unchangeable' then you can declare final const x and be done with it. The simpler the language is, the better.Simplistic does not mean simpler. Your system would be unable to express the simplest realities: void print(const char[] message); // not modifying message void main() { char[] myMessage = readln(); print(myMessage); // error! myMessage is changeable! } I truly think we've distilled the simplest language within our requirements. Andrei
Mar 16 2007
On Fri, 16 Mar 2007 11:02:39 -0700, Andrei Alexandrescu (See Website For Email) wrote:void print(const char[] message); // not modifying message void main() { char[] myMessage = readln(); print(myMessage); // error! myMessage is changeable! } I truly think we've distilled the simplest language within our requirements.Maybe the concepts but I'm not so sure about the usage. Given a function signature that has an array argument, there are two independant things we might want to remain unchangeable - the reference and the data referred to. To me, the signature ... void print(const char[] message) looks like 'const' is qualifying 'char[]' because that's what it is next to, and the 'message' looks like it is not qualified. So the signature looks like it is saying, the data is 'const' but the reference is not. Thus this below signature looks more like what you are trying to express ... void print(char[] const message) And to make both unchangeable then this looks better to me ... void print(const char[] const message) -- Derek Parnell Melbourne, Australia "Justice for David Hicks!" skype: derek.j.parnell
Mar 16 2007
Derek Parnell wrote:On Fri, 16 Mar 2007 11:02:39 -0700, Andrei Alexandrescu (See Website For Email) wrote:Exactly. All I'm saying is that if you go through the steps of your system, you will see that it's unable to implement the notion of modular mutability.void print(const char[] message); // not modifying message void main() { char[] myMessage = readln(); print(myMessage); // error! myMessage is changeable! } I truly think we've distilled the simplest language within our requirements.Maybe the concepts but I'm not so sure about the usage. Given a function signature that has an array argument, there are two independant things we might want to remain unchangeable - the reference and the data referred to. To me, the signature ... void print(const char[] message) looks like 'const' is qualifying 'char[]' because that's what it is next to, and the 'message' looks like it is not qualified. So the signature looks like it is saying, the data is 'const' but the reference is not.Thus this below signature looks more like what you are trying to express ... void print(char[] const message) And to make both unchangeable then this looks better to me ... void print(const char[] const message)We decided to use final to express symbol non-rebinding. Andrei
Mar 16 2007
On Fri, 16 Mar 2007 17:56:57 +0300, Dan <murpsoft hotmail.com> wrote:It was a joke.No, at first there must be 'D with macros' (like 'C with classes') and only then -- D++ :))*shudder*D already has templates. it shouldn't have a separate macro language. Having one indicates that the language itself somehow fails. Templates *should* be sufficient.My expirience in C++ and Ruby says that a language must have no macro system at all (like in Ruby) or must have a very powerful one (much more powerful than in C/C++, Nemerle is a fresh example). If D have started movement to support macros it must go as far as possible. I think.Using the ++ notation for the language is dangerous. It allows you to only upgrade once. You can't have a D, D++, D 2.0 etc, it just doesn't fit, 'causing the language to completely stagnate. Then someone else has to come along and invent a language E.E programming language already exists: http://www.erights.org/ ;) And it grows from the other side of BCPL-C-C++ family -- from Java's branch. So the name of D can't be changed to E, only to D++ or D 2.0 :)The simpler the language is, the better.Oberon was a very simple language, but where is it now? C++ have never been simple. Java isn't a simple language now. Ruby isn't simple. And this language are very successful in real world. And D will be, I hope. -- Regards, Yauheni Akhotnikau
Mar 16 2007
eao197 wrote:No, at first there must be 'D with macros' (like 'C with classes') and only then -- D++ :))D will get macros - but they won't be text processing macros, they'll be abstract syntax tree (AST) processing macros. C++ programmers often try to use text macros to do syntax tree manipulation, but the result usually looks like one tried to use a belt buckle to drive screws.
Mar 16 2007
On Sat, 17 Mar 2007 01:41:54 +0300, Walter Bright <newshound digitalmars.com> wrote:eao197 wrote:It is very interesting to hear that. Could you say more about the future macro system in D? Or it is a secret now?No, at first there must be 'D with macros' (like 'C with classes') and only then -- D++ :))D will get macros - but they won't be text processing macros, they'll be abstract syntax tree (AST) processing macros.C++ programmers often try to use text macros to do syntax tree manipulation, but the result usually looks like one tried to use a belt buckle to drive screws.Yes, I know. I have used C++ macros a lot in some cases. -- Regards, Yauheni Akhotnikau
Mar 17 2007
eao197 wrote:On Sat, 17 Mar 2007 01:41:54 +0300, Walter Bright <newshound digitalmars.com> wrote:It's pretty simple: macro foo(args) { ...syntax that gets inserted... } and the args and syntax is evaluated in the context of the invocation of the macro, not the definition of the macro. You'll be able to do things like: macro print(arg) { writefln(__FILE__, __LINE__, arg); } which get the file and line in the right context. There's no way to do that right now.eao197 wrote:It is very interesting to hear that. Could you say more about the future macro system in D? Or it is a secret now?No, at first there must be 'D with macros' (like 'C with classes') and only then -- D++ :))D will get macros - but they won't be text processing macros, they'll be abstract syntax tree (AST) processing macros.
Mar 17 2007
Funny, this is beginning to read like dialogue from Sam & Max: Episode 1... Daniel Keep wrote:Walter Bright wrote:Bosco: And I might have another item of interest behind the counter...eao197 wrote:On Sat, 17 Mar 2007 01:41:54 +0300, Walter Bright <newshound digitalmars.com> wrote:D will get macros - but they won't be text processing macros, they'll be abstract syntax tree (AST) processing macros.Sam: I accept your thinly veiled invitation to ask about the item behind the counter.It is very interesting to hear that. Could you say more about the future macro system in D? Or it is a secret now?Bosco: Oh, it's a little something I like to call a Tear Gas Grenade Launcher.It's pretty simple: macro foo(args) { ...syntax that gets inserted... }Oh, VERY slick.Max: "Tear Gas Grenade Launcher?" Oh, I *really* want that!Bosco: It'll clear out a room full of militant college students in no time; guaranteed!and the args and syntax is evaluated in the context of the invocation of the macro, not the definition of the macro. You'll be able to do things like: macro print(arg) { writefln(__FILE__, __LINE__, arg); } which get the file and line in the right context. There's no way to do that right now.Wow. <3Max: I feel really close to you right now. :P Question: in terms of usage, will these macros be like functions? Or will we able to define, say, a new kind of control structure with keywords? Or perhaps even a construct with a trailing curly brace block? You spoil us Walter, you really do. -- Daniel -- Unlike Knuth, I have neither proven or tried the above; it may not even make sense. v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
Mar 17 2007
Daniel Keep wrote:Question: in terms of usage, will these macros be like functions?Yes. No !( ) syntax.Or will we able to define, say, a new kind of control structure with keywords?No. Abner Hale thwacks such things with "abomination!"Or perhaps even a construct with a trailing curly brace block?Yes.You spoil us Walter, you really do.macros should be the final piece needed to make DSL's work nicely, and they are actually rather simple conceptually and implementation-wise. I tried for a long time to figure out how to make templates do the work, until I finally realized that AST macros are *fundamentally different* from templates. A nice side benefit to macros is we should be able to deprecate lazy.
Mar 17 2007
Walter Bright wrote:macros should be the final piece needed to make DSL's work nicely, and they are actually rather simple conceptually and implementation-wise. I tried for a long time to figure out how to make templates do the work, until I finally realized that AST macros are *fundamentally different* from templates.Yup. It sounds like the implementation will really be quite like the new mixin feature wrapped in some syntactic sugar. Oddly, I'm actually looking forward to this. There have been a few instances where I actually needed macros... some being cases where I wanted to define a local template function (which is illegal), and others for more bizarre uses.A nice side benefit to macros is we should be able to deprecate lazy.I actually like 'lazy' for a narrow range of uses. It makes creating an optimal debug logger exceedingly simple, for example. Compared to all the evil tricks Matthew needed for Pantheios, 'lazy' has a clear and measurable benefit. But if the same thing could be accomplished using macros then so much the better. Sean
Mar 17 2007
Walter Bright wrote:It's pretty simple: macro foo(args) { ...syntax that gets inserted... } and the args and syntax is evaluated in the context of the invocation of the macro, not the definition of the macro. You'll be able to do things like: macro print(arg) { writefln(__FILE__, __LINE__, arg); } which get the file and line in the right context. There's no way to do that right now.And what about mixin templates? Couldn't they just be fixed to do this work? From docs: " Unlike a template instantiation, a template mixin's body is evaluated within the scope where the mixin appears, not where the template declaration is defined. It is analogous to cutting and pasting the body of the template into the location of the mixin. It is useful for injecting parameterized 'boilerplate' code, as well as for creating templated nested functions, which is not possible with template instantiations. " For me it looks exactly like this what you want to do with macro. What would be a difference? For me it seems that the whole mixin thing is rather buggy and unusfull at the moment - for reference see: http://www.digitalmars.com/d/archives/digitalmars/D/learn/3412.html#N3416 -- Regards Marcin Kuszczak (Aarti_pl) ------------------------------------- Ask me why I believe in Jesus - http://zapytaj.dlajezusa.pl (en/pl) Doost (port of few Boost libraries) - http://www.dsource.org/projects/doost/ -------------------------------------
Mar 17 2007
Walter Bright wrote:eao197 wrote:On naming why not use mixin, since they are so similar? mixin print(arg) { } Then make them typesafe (using alias to get out of type-safty)? What if you want the file in some other context? It would be nice to have a complete solution to that, which allows some sort of stack traversal. Although I'm not sure its possible, due to not wanting to keep this sort of information around at release time. ie: macro print(arg) { writefln(__FILE__[stack_level], __LINE__[stack_level], arg); } Or even better: Stack[0].Line; //Current line Stack[1].Line; //Line one level up Stack[0].File; Stack[0].Module; Stack[0].Function; Stack[0].NumbArgs; //Some form of reflection Stack[0].Arg[N]; //Access to the value of the argument (ie Turple of values) Stack[0].ArgIdentifier[N] //String name of the identifier Stack[0].FuncType //The type of function we are in (is it a macro, a compile time function a member, a regular function) ect... macro print(arg) { with(Stack[0]) { writefln(File, Line, arg); } } I guess that would have problems for larger depths. Perhaps it could be limited to two levels (current and parent) or only work for ones that can be evaluated at compile time (you would get a compile time error if the line number couldn't be evaluated.) There could be a debug version that would work at run time. -JoelOn Sat, 17 Mar 2007 01:41:54 +0300, Walter Bright <newshound digitalmars.com> wrote:It's pretty simple: macro foo(args) { ...syntax that gets inserted... } and the args and syntax is evaluated in the context of the invocation of the macro, not the definition of the macro. You'll be able to do things like: macro print(arg) { writefln(__FILE__, __LINE__, arg); } which get the file and line in the right context. There's no way to do that right now.eao197 wrote:It is very interesting to hear that. Could you say more about the future macro system in D? Or it is a secret now?No, at first there must be 'D with macros' (like 'C with classes') and only then -- D++ :))D will get macros - but they won't be text processing macros, they'll be abstract syntax tree (AST) processing macros.
Mar 17 2007
On Sat, 17 Mar 2007 11:49:59 +0300, Walter Bright <newshound digitalmars.com> wrote:It's pretty simple: macro foo(args) { ...syntax that gets inserted... } and the args and syntax is evaluated in the context of the invocation of the macro, not the definition of the macro. You'll be able to do things like: macro print(arg) { writefln(__FILE__, __LINE__, arg); } which get the file and line in the right context. There's no way to do that right now.As I can see the content of macro body will be inserted into AST in the place of invocation. But there is not much differences with existing C/C++ macro handling (insertion of right __FILE__, __LINE__ is good thing anyway). Is there allowed any access to previous parsed entity? For example, can I define macro: macro some_class_extender(class_name) { ...modification of 'class_name' class structure... } class MyCoolClass { ... } some_class_extender( MyCoolClass ); and get the modified version of MyCoolClass after some_class_externder invocation? -- Regards, Yauheni Akhotnikau
Mar 17 2007
Andrei Alexandrescu (See Website For Email) Wrote:Bruno Medeiros wrote:So, would this allow you to express the associative array requirement, that the key must never be changed after it is set? char[] myKey = "foo"; myAA[myKey] = "bar"; myKey = "something else"; // ERROR: this stuffs up the AA would you write the getter's signature as superconst? T set(super const K key) {...} Is super const allowed as a parameter type?What is the status of the experimental designs for the "storage classes" manipulation that Andrei and others where thinking of for D. The last I heard from it was Andrei's max suggestion from his max design challenge, however, I think that suggestion may suffer from some problems in regards to the "maxtype" requirement, plus it is wholly incomplete in regards to how storage classes interact between each other. Like Andrei said, what is a "const inout lazy const char[]", if valid at all? Is there any news here? Is there a working(aka complete) design?We have talked about a design. In short, the intent is to define three flavors of immutability: a) final - a simple storage class controlling the immutability of the bits allocated for the symbol per se; b) const - type qualifier meaning an immutable view of an otherwise modifiable data. const does not control the bits of the object, only the storage addressed indirectly by it (transitively); c) "superconst" - denoted as "const!" or "super const": type qualifier meaning that the data is genuinely unmodifiable. There is talk about deprecating lazy if it's best implemented via other mechanisms. There is also talk about deprecating "inout" in favor of "ref" on grounds that the often-useful "inout const" is likely to become To read a declaration like "const inout lazy const char[]", you can first parenthesize it appropriately: const(inout(lazy(const(char[])))) The lazy thing is really a delegate that returns a const char[]. The inout around it passes that delegate by reference, and the const at the top makes the delegate immutable. Andrei
Mar 16 2007
Reiner Pope wrote:Andrei Alexandrescu (See Website For Email) Wrote:Yes. AndreiBruno Medeiros wrote:So, would this allow you to express the associative array requirement, that the key must never be changed after it is set? char[] myKey = "foo"; myAA[myKey] = "bar"; myKey = "something else"; // ERROR: this stuffs up the AA would you write the getter's signature as superconst? T set(super const K key) {...} Is super const allowed as a parameter type?What is the status of the experimental designs for the "storage classes" manipulation that Andrei and others where thinking of for D. The last I heard from it was Andrei's max suggestion from his max design challenge, however, I think that suggestion may suffer from some problems in regards to the "maxtype" requirement, plus it is wholly incomplete in regards to how storage classes interact between each other. Like Andrei said, what is a "const inout lazy const char[]", if valid at all? Is there any news here? Is there a working(aka complete) design?We have talked about a design. In short, the intent is to define three flavors of immutability: a) final - a simple storage class controlling the immutability of the bits allocated for the symbol per se; b) const - type qualifier meaning an immutable view of an otherwise modifiable data. const does not control the bits of the object, only the storage addressed indirectly by it (transitively); c) "superconst" - denoted as "const!" or "super const": type qualifier meaning that the data is genuinely unmodifiable. There is talk about deprecating lazy if it's best implemented via other mechanisms. There is also talk about deprecating "inout" in favor of "ref" on grounds that the often-useful "inout const" is likely to become To read a declaration like "const inout lazy const char[]", you can first parenthesize it appropriately: const(inout(lazy(const(char[])))) The lazy thing is really a delegate that returns a const char[]. The inout around it passes that delegate by reference, and the const at the top makes the delegate immutable. Andrei
Mar 16 2007
Andrei Alexandrescu (See Website For Email) Wrote:We have talked about a design. In short, the intent is to define three flavors of immutability: a) final - a simple storage class controlling the immutability of the bits allocated for the symbol per se; b) const - type qualifier meaning an immutable view of an otherwise modifiable data. const does not control the bits of the object, only the storage addressed indirectly by it (transitively); c) "superconst" - denoted as "const!" or "super const": type qualifier meaning that the data is genuinely unmodifiable.'invariant' seems to be the consensus (instead of super const or const!)? If so, I'd agree that's the best of the three.There is talk about deprecating lazy if it's best implemented via other mechanisms. There is also talk about deprecating "inout" in favor of "ref" on grounds that the often-useful "inout const" is likely to becomeI haven't noticed 'ref' come-up on subsequent posts, but I would strongly favor this change as well. - Dave
Mar 23 2007
Bill Baxter Wrote:is *already* unreadable (plus I don't think that [3,17] part is legal D). If any reasonable programmer really did have a need for such a typeActually, Bill, it's part of the language spec. http://digitalmars.com/d/arrays.html Look up "Rectangular Arrays"
Mar 16 2007
Dan wrote:Bill Baxter Wrote:The only thing even close to that is this: --- In other languages, this would be called a multidimensional array and be declared as: double matrix[3,3]; --- Note those first three words...is *already* unreadable (plus I don't think that [3,17] part is legal D). If any reasonable programmer really did have a need for such a typeActually, Bill, it's part of the language spec. http://digitalmars.com/d/arrays.html Look up "Rectangular Arrays"
Mar 16 2007
Dan wrote:Bill Baxter Wrote:Read that part of the spec closely, Dan. --bbis *already* unreadable (plus I don't think that [3,17] part is legal D). If any reasonable programmer really did have a need for such a typeActually, Bill, it's part of the language spec. http://digitalmars.com/d/arrays.html Look up "Rectangular Arrays"
Mar 16 2007
Andrei Alexandrescu (See Website For Email) Wrote:We have talked about a design. In short, the intent is to define three flavors of immutability: a) final - a simple storage class controlling the immutability of the bits allocated for the symbol per se; b) const - type qualifier meaning an immutable view of an otherwise modifiable data. const does not control the bits of the object, only the storage addressed indirectly by it (transitively); c) "superconst" - denoted as "const!" or "super const": type qualifier meaning that the data is genuinely unmodifiable.Is there anything in your discussion about compile-time constants (the sort that you need for 'static if', etc) ? You spoke a while ago about improving compile-time evaluation syntax so that there would be no difference at the call site between runtime and compile-time evaluation (like for regexps). It seems like you could get this quite easily by adding just one more parameter modifier (is this a storage class? I'm not sure) to denote, "any time this function is called, this parameter must be known at compile-time". Effectively, it would just be a conversion from this: RegExpMatch match(static const char[] pattern, char[] text) {...} ... main() { match("gr[ae]y", din.read()); } to this: RegExpMatch match(char[] pattern)(char[] text) {...} ... main() { match!("gr[ae]y")(din.read()); } Any plans this way? Cheers, Reiner
Mar 16 2007
Reiner Pope wrote:Andrei Alexandrescu (See Website For Email) Wrote:I understand this is high on Walter's list. The syntax discussed is: // dispatched when the pattern is known at compile time RegExpMatch match(const char[] p)(const char[] p, char[] text) {...} // dispatched when the pattern is a runtime string RegExpMatch match()(const char[] p, char[] text) {...}We have talked about a design. In short, the intent is to define three flavors of immutability: a) final - a simple storage class controlling the immutability of the bits allocated for the symbol per se; b) const - type qualifier meaning an immutable view of an otherwise modifiable data. const does not control the bits of the object, only the storage addressed indirectly by it (transitively); c) "superconst" - denoted as "const!" or "super const": type qualifier meaning that the data is genuinely unmodifiable.Is there anything in your discussion about compile-time constants (the sort that you need for 'static if', etc) ? You spoke a while ago about improving compile-time evaluation syntax so that there would be no difference at the call site between runtime and compile-time evaluation (like for regexps).It seems like you could get this quite easily by adding just one more parameter modifier (is this a storage class? I'm not sure) to denote, "any time this function is called, this parameter must be known at compile-time". Effectively, it would just be a conversion from this: RegExpMatch match(static const char[] pattern, char[] text) {...} ... main() { match("gr[ae]y", din.read()); } to this: RegExpMatch match(char[] pattern)(char[] text) {...} ... main() { match!("gr[ae]y")(din.read()); } Any plans this way?The above forces only compile-time constant regexps. What we need is to dispatch depending on compile-time constant vs. run-time string. Combined with macros, this will essentially allow a call to writefln to morph, depending on its arguments, into putch(), fputs(), write(), fprintf() - or execute today's dynamically-checked writefln. Andrei
Mar 16 2007
Andrei Alexandrescu (See Website For Email) wrote:Reiner Pope wrote:Good to hear that. The syntax discussed is:Andrei Alexandrescu (See Website For Email) Wrote:I understand this is high on Walter's list.We have talked about a design. In short, the intent is to define three flavors of immutability: a) final - a simple storage class controlling the immutability of the bits allocated for the symbol per se; b) const - type qualifier meaning an immutable view of an otherwise modifiable data. const does not control the bits of the object, only the storage addressed indirectly by it (transitively); c) "superconst" - denoted as "const!" or "super const": type qualifier meaning that the data is genuinely unmodifiable.Is there anything in your discussion about compile-time constants (the sort that you need for 'static if', etc) ? You spoke a while ago about improving compile-time evaluation syntax so that there would be no difference at the call site between runtime and compile-time evaluation (like for regexps).// dispatched when the pattern is known at compile time RegExpMatch match(const char[] p)(const char[] p, char[] text) {...} // dispatched when the pattern is a runtime string RegExpMatch match()(const char[] p, char[] text) {...}That seems fine, but I can't help wondering, "why the double-declaration of p in the first instance?" and also, "why does the second instance of match even need to be a template?".Well, I kind of took it for granted that the above suggestion would allow for overloading by compile-time-constness (with a preference to the compile-time version when there's a choice). So that you could write: RegExpMatch match(static const char[] pattern, char[] text){...} RegExpMatch match(char[] pattern, char[] text) {...}It seems like you could get this quite easily by adding just one more parameter modifier (is this a storage class? I'm not sure) to denote, "any time this function is called, this parameter must be known at compile-time". Effectively, it would just be a conversion from this: RegExpMatch match(static const char[] pattern, char[] text) {...} ... main() { match("gr[ae]y", din.read()); } to this: RegExpMatch match(char[] pattern)(char[] text) {...} ... main() { match!("gr[ae]y")(din.read()); } Any plans this way?The above forces only compile-time constant regexps. What we need is to dispatch depending on compile-time constant vs. run-time string.Combined with macros, this will essentially allow a call to writefln to morph, depending on its arguments, into putch(), fputs(), write(), fprintf() - or execute today's dynamically-checked writefln.True. I was also interested in another use of this, though: allowing a library-time implementation of tuples (since what kind of feature is one that can't be implemented in the library?). There are basically two reasons that this can't be done at the moment: alias Tuple!(int, double) myTuple; myTuple[0] = 5; // First reason foreach (val; myTuple) // Second reason { writef(val); } I would imagine that you could implement the first feature as: struct MyTupleImpl(TypeList...) { ... TypeList[i] opIndex(static const int i) {...} // We grab the return type based on the parameter, so we must know it at compile time. It makes no sense to have a runtime version of this. } and at a stretch, you could imagine the second feature as working in a similar way: your compile-time representation of the foreach delegate is either a char[] to be mixed in, or an expression alias, when we get that: struct MyTupleImpl(TypeList...) { int opApply(static const char[] code) { // iterate through tuple; this iteration would actually have to be generated with CTFE, but you get the idea { TypeList[i] __special_foreach_key = whatever; mixin(code); } } } Cheers, Reiner
Mar 16 2007
Reiner Pope wrote:Andrei Alexandrescu (See Website For Email) wrote:Good question. It must be a template by the pigeonhole principle: each compile-time regex generates in theory different code, so you must have as many distinct functions as strings.Reiner Pope wrote:Good to hear that. The syntax discussed is:Andrei Alexandrescu (See Website For Email) Wrote:I understand this is high on Walter's list.We have talked about a design. In short, the intent is to define three flavors of immutability: a) final - a simple storage class controlling the immutability of the bits allocated for the symbol per se; b) const - type qualifier meaning an immutable view of an otherwise modifiable data. const does not control the bits of the object, only the storage addressed indirectly by it (transitively); c) "superconst" - denoted as "const!" or "super const": type qualifier meaning that the data is genuinely unmodifiable.Is there anything in your discussion about compile-time constants (the sort that you need for 'static if', etc) ? You spoke a while ago about improving compile-time evaluation syntax so that there would be no difference at the call site between runtime and compile-time evaluation (like for regexps).// dispatched when the pattern is known at compile time RegExpMatch match(const char[] p)(const char[] p, char[] text) {...} // dispatched when the pattern is a runtime string RegExpMatch match()(const char[] p, char[] text) {...}That seems fine, but I can't help wondering, "why the double-declaration of p in the first instance?" and also, "why does the second instance of match even need to be a template?".That's not on the list yet. One thing at a time :o). AndreiWell, I kind of took it for granted that the above suggestion would allow for overloading by compile-time-constness (with a preference to the compile-time version when there's a choice). So that you could write: RegExpMatch match(static const char[] pattern, char[] text){...} RegExpMatch match(char[] pattern, char[] text) {...}It seems like you could get this quite easily by adding just one more parameter modifier (is this a storage class? I'm not sure) to denote, "any time this function is called, this parameter must be known at compile-time". Effectively, it would just be a conversion from this: RegExpMatch match(static const char[] pattern, char[] text) {...} ... main() { match("gr[ae]y", din.read()); } to this: RegExpMatch match(char[] pattern)(char[] text) {...} ... main() { match!("gr[ae]y")(din.read()); } Any plans this way?The above forces only compile-time constant regexps. What we need is to dispatch depending on compile-time constant vs. run-time string.Combined with macros, this will essentially allow a call to writefln to morph, depending on its arguments, into putch(), fputs(), write(), fprintf() - or execute today's dynamically-checked writefln.True. I was also interested in another use of this, though: allowing a library-time implementation of tuples (since what kind of feature is one that can't be implemented in the library?). There are basically two reasons that this can't be done at the moment: alias Tuple!(int, double) myTuple; myTuple[0] = 5; // First reason foreach (val; myTuple) // Second reason { writef(val); } I would imagine that you could implement the first feature as: struct MyTupleImpl(TypeList...) { ... TypeList[i] opIndex(static const int i) {...} // We grab the return type based on the parameter, so we must know it at compile time. It makes no sense to have a runtime version of this. } and at a stretch, you could imagine the second feature as working in a similar way: your compile-time representation of the foreach delegate is either a char[] to be mixed in, or an expression alias, when we get that: struct MyTupleImpl(TypeList...) { int opApply(static const char[] code) { // iterate through tuple; this iteration would actually have to be generated with CTFE, but you get the idea { TypeList[i] __special_foreach_key = whatever; mixin(code); } } }
Mar 17 2007
Andrei Alexandrescu (See Website For Email) wrote:Reiner Pope wrote:But how about the runtime implementation of match()? There's no code generation there...Andrei Alexandrescu (See Website For Email) wrote:Good question. It must be a template by the pigeonhole principle: each compile-time regex generates in theory different code, so you must have as many distinct functions as strings.Reiner Pope wrote:Good to hear that. The syntax discussed is:Andrei Alexandrescu (See Website For Email) Wrote:I understand this is high on Walter's list.We have talked about a design. In short, the intent is to define three flavors of immutability: a) final - a simple storage class controlling the immutability of the bits allocated for the symbol per se; b) const - type qualifier meaning an immutable view of an otherwise modifiable data. const does not control the bits of the object, only the storage addressed indirectly by it (transitively); c) "superconst" - denoted as "const!" or "super const": type qualifier meaning that the data is genuinely unmodifiable.Is there anything in your discussion about compile-time constants (the sort that you need for 'static if', etc) ? You spoke a while ago about improving compile-time evaluation syntax so that there would be no difference at the call site between runtime and compile-time evaluation (like for regexps).// dispatched when the pattern is known at compile time RegExpMatch match(const char[] p)(const char[] p, char[] text) {...} // dispatched when the pattern is a runtime string RegExpMatch match()(const char[] p, char[] text) {...}That seems fine, but I can't help wondering, "why the double-declaration of p in the first instance?" and also, "why does the second instance of match even need to be a template?".That's not on the list yet. One thing at a time :o).Sure thing. It's just that we've already got so much more after D 1.0 that I can't help wanting more :o). Cheers, Reiner
Mar 17 2007
Andrei Alexandrescu (See Website For Email) wrote:Combined with macros, this will essentially allow a call to writefln to morph, depending on its arguments, into putch(), fputs(), write(), fprintf() - or execute today's dynamically-checked writefln.So is there going to be a way to specify at the function (or template) definition site that the function (or template) produces a compile-time string which is to be mixed into the call site. eg: // The 'mixin' specifies that the result should be mixed into the call site. mixin char[] writefln(/*params*/) { ... // Generate code return generatedCode; } Sounds good. Reiner
Mar 17 2007
Bruno Medeiros wrote:What is the status of the experimental designs ...I asked this because yesterday, out of nowhere, I started thinking about this problem, and as a kind of a mental exercise I came to a working design. It seems kinda pointless, since you already made your design, but I'll show this one nevertheless. Consider it a late entry to the max challenge :P . Still, there are some aspects presented here, that I don't how they would work on your planned design (like those keyed by the questions). Most of the terms here are tentative, and so is the syntax. Please consider the syntax separately from the semantics and conceptualization. Errors may be present in the text. This design is presented as is, without any warranty of any kind. :P CONCEPTUALIZATION There are 3 major kinds of D entities: Values (expressions), types, and templates. (and labels too I guess...) Values are characterized by properties that define what one can do with the value. The most important of these properties is the type. D offers a very rich mechanism to query and manipulate types (typeof(..), is(..) expression, auto, type parameters, etc.), much better than any other statically typed language I know. But the type is not the only "property" of an expression. There are others, such as whether an expression is an lvalue or not, if it can be assigned, etc.. The problem so far is that D does not offer a good mechanism to query and manipulate such "type properties". Let's consider the following type properties: R: is the value readable. C: is the value readable at compile time (compile time constant). &: is the value referenciable. W: is the value writable. (explained later) I can't find a good term for these "extended type properties" or "extended value properties" so I'll just call it QUX for now. Silly, I know, but whatever. And I will call "core type" to the current notion of type, which is what typeof(..) returns. So, with these QUX, what are the valid combinations of them? They are: R CR R& RW& W& (I'm skipping the explanation of why, since I think that's clear, see examples below). Furthermore, these property combinations are related in the following hierarchy of conversion: R / \ CR R& W& \ / RW& Examples of the QUX for various values in current D: 42 // CR - A literal is a constant. var // RW& - As in: int var; fvar // R& - As in: const fvar; fvar = 2; It's like 'final' func() // R - the value of a function is readonly and not referenciable // W - No example in current D for W Let's give some tentative keywords for the possible QUX combinations: CR - const RW& - ref W& - wronly ref R& - rdonly ref R - rdonly Now, recall the following: QUX describe the properties of a value. The first thing you may think now is that one can use QUX to declare variables of the same QUX type. That's not entirely accurate. For example you can't declare a variable of QUX R, because a var is always either referenciable, or a (compile-time) constant. There are no R variables. Specifying a var as rdonly will create a R&. Specifying no QUX will create a RW&. Specifying ref in a var declaration will alse create a RW& var, but the identity will be the same as the var in the given initializer. ref will preserve the "reference" (memory location) of the initializer. This is mentioned to clear the declaration semantics. Examples: int varA = varX; // var is RW& const int varB = 1; // var is CR rdonly int varC = 2; // var is R& rdonly ref int varD = &varX; // var is RW& too wronly ref int varE = &varX; // var is W& varA will be a copy of varX, while varD will be the same as varX (same identity). After definition, varA and varD will have the same QUX. And what about the definitions of function parameters, and function return types? There are some minor differences. In function return types, if no QUX is specified, then the QUX is rdonly (as it is currently in D). In function parameters, if no QUX is specified the QUX is rdonly too (this is different from current D, but is considered a nice improvement. Function arguments are almost never modified anyway). What about composing types? That is, when one has a composite type (array, pointers, etc.), how does one specify QUX for each of the type components? Well for this var: int[]* var; then QUX are specified like this: rdonly int[]* var; // var (the pointer) is rdonly (rdonly int[])* var; // the pointer target (the array) is rdonly (rdonly int)[]* var; // the members of the array are rdonly rdonly (rdonly (rdonly int)[])* var; // All are rdonly Note that some QUX don't make sense in certain declarations, like declaring an array member as ref, like this: (ref int)[] var; because the members of arrays are refs already. This could be an error or simply ignored. What about auto? auto does not in any way capture the QUX, just the core type (as in typeof(..) ). rdonly var; auto foo = var; // foo is not rdonly How do we templatize and parameterize QUX? Let's see by example, looking at previous design challenges: The id function: T id(expr T) (T a) { return a; } So, "expr T" denotes that T is not a normal type parameter, but an "extended type parameter". Besides the core type, it will also hold information about the QUX. id can be instanced manually or with IFTI. manipulation, but let's first recall what max does. Consider these vars: a = 3; b = 9; const fvar; // fvar is 'final' fvar = 1; And now some examples of max usage: max(1, 2) 2 of QUX CR max(a, 2) a of QUX R max(a, b) b of QUX RW& max(a, func()) a of QUX R max(a, fvar) a of QUX R& As requested, max preservers the greatest common QUX information. Here's how we define max: maxExtType!(A,B) max(expr A :: rdonly, expr B :: rdonly) (A a, B b) { if(a >= b) return a; else return b; } Of note: The 'T :: U' syntax means specialize the template if T can be converted to U. This is a variant of the current 'T : U' syntax which means specialize if T is the *same* as U. In both these constructs, U can be a QUX, but only if T is an "extended type parameter" (a parameter declared with expr). maxExtType is the key to complete the challenge. It defines the maximum common extended type of A and B. This is defined as: template maxExtType(expr A, expr B) { static if( !is(typeof(A) == typeof(B)) ) { alias maxCoreType(A, B) maxType; // Type cannot be ref } else { static if( is(A == ref) && is(B == ref)) alias (ref typeof(A)) maxType; else static if( is(A :: rdonly ref) && is(B :: rdonly ref)) alias (rdonly ref typeof(A)) maxType; else static if( is(A :: wronly ref) && is(B :: wronly ref) ) alias (wronly typeof(A)) maxType; else static if( is(A :: rdonly) && is(B :: rdonly) ) alias (rdonly typeof(A)) maxType; else static assert(false, "No common extended type for:"+A+" and "+B); } } So, like mentioned in the original challenge thread, if the core type of A and B are not the same, then maxExtType cannot be a ref. That's what the first static if checks for (note: an exception can be made for object types). The subsequent static ifs check for increasingly less restrictive common QUXs. It's possible that a common QUX does not exist if one is R& and the other is W& for example. What about lazy? In this design, lazy simply isn't considered as a QUX, as it simply is not a property of an expression. There are no lazy expressions. After a lazy FOO variable is created (which must be initialized), the variable becomes for *all effects* indistinguishable from a FOO delegate() , that is, a delegate returning type FOO. Thus, lazy can't also be parameterized/templatized. IMMUTABILITY Immutability, as in, "transitive immutability" is achieved as a type modifier with the keyword "immut". An immut value means that any other member obtained from the original value cannot be modified, and so on. The members of immut values are rdonly and immut. immut is not a QUX, it is a type modifier that modifies (and is part of) the core type. This means that immut appears in "typeof(..)", and consequentely is also captured by auto. This is the only sensible behavior, since immut describes a property of the referenced data of that expression, and must be preserved upon assignments (and thus part of the core type). This is unlike QUX, since QUX only describe properties of the immediate-value of an expression, which is copied in assignments. I.e., you can assign a rdonly value to a non-rdonly var, but you can't assign an immut value to a non-immut (normal) var. This shows how immut and QUX are somewhat different in nature. Also immut vars and not automatically rdonly, they are rdonly only if 'rdonly' is also specified. An example: immut Foo[] fooar; then: typeof(fooar[0]) == rdonly immut Foo; TODO *Syntax to specify the "this" of a method as immut. Maybe do it like C++? *A way to conveniently specify/templatize methods that are identical and only vary in the mutability of it's types (like 'romaybe' in Javari). The following describes a particular use case for rdonly and wronly: VARIANT COMPOSITE TYPES. Consider this hierarchy: FooBar extends Foo extends Object Xpto extends Object Suppose we have an array of Foo: Foo[] fooarr; The classic contravariance problem is, is fooarr safely castable to Object[] ? On first sight one might think yes, since Foo is an Object, then Foo[] is an Object[]. But that is not the case since an Object[] array is an array that one can put an Xpto object into: (cast(Object[]) fooarr)[0] = new Xpto(); which would break type safety, since we would have a Xpto in an array of Foo's. What happens is that we have some array operations (like readers) that remain safe , but others do not (like writers). Java allows that cast, but has runtime checks on array member assignments, and throws an exception if the type safety is violated like in the example above. Can a language provide (compile time) support for safe casting? With rdonly and wronly it can. We have that Foo[] cannot be cast to Object[], but it can be safely cast to (rdonly Object)[]. And then: fooarr2 = cast((rdonly Object)[]) fooarr; fooarr2[0] = new Xpto(); // Not allowed fooarr2[0].doSomething(); // Allowed Assignments won't be allowed, but reading is allowed. Conversely, the array type parameter can be contravariantly cast, from Foo[] to (wronly Foobar)[]. // Ok because fooarr[] is of type wronly FooBar fooarr[0] = new FooBar(); // Not allowed because you can't read fooarr[0]; fooarr[0].doSomething(); This was the main motivation I saw for the use of wronly, however, this mechanism is quite simple (as in, simplistic) and limited. It's not as powerful as Java's generics, which allow a greater degree of functionality with lower-bounded types. As such, it may not be worth having wronly just because of this. Still, I guess wronly could also be used in place of 'out' parameters. SYNTAX AND TERMS SUBJECT TO CHANGE: QUX - EVT (Extended Value Properties) or ETP (Extended Type Properties) ? Or 'attributes' instead of 'properties' ? But definitely not "storage class", that term sucks. :o immut - perhaps 'immutable'? rdonly - perhaps 'readonly' or 'final'? wronly - perhaps 'writeonly'? expr "::" - Ideally, it would be better that the ":" of template specialization would behave the same as the ":" of the is(..) expression. Comments are welcome. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Mar 17 2007
Andrei Alexandrescu (See Website For Email) Wrote:Bruno Medeiros wrote:I didn't see any discussion of how a member function is to be marked as being const or non const, as in C++. Does that mean that there are plans to make the compiler figure out which methods are const by itself ? To do this successfully will require some way of expressing aggregation. So that the compiler can distinguish between a reference that a class may hold simply to 'look at' another class from a reference that it holds representing a 'is part of' relationship. In C++ agregation could be expressed by simply not using a pointer, or if polymorphism or other reasons to use a pointer required, an aggregate pointer could be defined, such as : template <typename T> class aggregate_ptr { T * p; //dtors ctors etc. const T * operator->() const { return p; } T * operator->() { return p; } }; Here operator -> is overloaded to so that use of this pointer as a member variable is a way of expressing aggregation. ie the pointed to class is considered part of the class the pointer is part of for const purposes.What is the status of the experimental designs for the "storage classes" manipulation that Andrei and others where thinking of for D. The last I heard from it was Andrei's max suggestion from his max design challenge, however, I think that suggestion may suffer from some problems in regards to the "maxtype" requirement, plus it is wholly incomplete in regards to how storage classes interact between each other. Like Andrei said, what is a "const inout lazy const char[]", if valid at all? Is there any news here? Is there a working(aka complete) design?We have talked about a design. In short, the intent is to define three flavors of immutability: a) final - a simple storage class controlling the immutability of the bits allocated for the symbol per se; b) const - type qualifier meaning an immutable view of an otherwise modifiable data. const does not control the bits of the object, only the storage addressed indirectly by it (transitively); c) "superconst" - denoted as "const!" or "super const": type qualifier meaning that the data is genuinely unmodifiable. There is talk about deprecating lazy if it's best implemented via other mechanisms. There is also talk about deprecating "inout" in favor of "ref" on grounds that the often-useful "inout const" is likely to become To read a declaration like "const inout lazy const char[]", you can first parenthesize it appropriately: const(inout(lazy(const(char[])))) The lazy thing is really a delegate that returns a const char[]. The inout around it passes that delegate by reference, and the const at the top makes the delegate immutable. Andrei
Mar 18 2007
I think I've got this. Is the following right? *final variables can be assigned only once in their lifetime, but are otherwise normal variables (i.e. they *do* have a memory address), except where constant folded by the compiler (this should be completely transparent to the programmer). *const and invariant only make sense when applied to references, otherwise they are ignored or (preferably) errors. *const references cannot be used to mutate the data they reference, but the data they reference may be mutated directly or through other non-const, non-invariant references. *invariant references only reference data that will never be mutated (e.g. final variables). *Both const and invariant references can be reassigned unless they are also final references. *Conversely, when final is applied to the declaration of a reference, only that reference is protected from mutation, not the data it references, unless that reference is also const or invariant. *Neither const nor invariant references can be cast to non-const or non-invariant references directly. *The address of any variable or the value of any reference (of compatible type) can be assigned to const references. *Only the addresses of final variables (I'm sure of this), the direct result of "new" statements (not sure on this one), and the values of other invariant references may be assigned to invariant references. *const and invariant are viral (i.e. all references in the data referenced by a const or invariant reference is also const or invariant, respectively, when access through the const or invariant reference). *final, when applied directly to POD structures (structs and array references), means no members of that structure can be modified after assignment, but is non-viral to references within the POD structure. (Not sure on this.) *Function declarations cannot overloaded based on const or invariant. (Pretty sure on this.) --------------------- Here are a whole bunch of contrived examples of most of these rules: final int w = 5; //legal final int x = 55; //ditto int y = 6; //legal int z; //ditto const int i; //either (preferably) illegal or ignored invariant int i; //ditto x = 6; //illegal y = 7; //legal int* mut_pointer; mut_pointer = &x; //illegal: this would allow x to be mutated mut_pointer = &y; //obviously legal *mut_pointer = 10; //obviously legal const int* const_pointer; const_pointer = &x; //legal const_pointer = &y; //Also legal: const_pointer is mutable (non-final) z = *const_pointer; //Legal: you can read through const references *const_pointer = 10; //illegal: you can't mutate through const references invariant int* inv_pointer = &x; //Legal: x is final and never changes inv_pointer = &y //Illegal: y is non-final may change inv_pointer = &w; //Legal: inv_pointer is mutable (non-final) y = *inv_pointer; //Legal: data can be read through inv_pointer *inv_pointer = y; //Illegal: you can't mutate through invariant references final int* final_pointer = &y; //obviously legal z = *final_pointer; //obviously legal *final_pointer = 2; //legal: y can be changed through final_pointer final_pointer = &z; //illegal: final_pointer already assigned final int* final_pointer2 = &x; //illegal: final_pointer2 allows mutation final const int* final_const_pointer = &x; //Legal: const pointer does not allow mutation final_const_pointer = &w; //Illegal: final_const_pointer is final and cannot be mutated y = *final_const_pointer; //Obviously legal *final_const_pointer = y; //Obviously illegal final const int* final_const_pointer2 = &y; //Legal: neither y nor const care about underlying mutability final invariant int* final_inv_pointer = &x; //Legal final invariant int* final_inv_pointer2 = &y; //Illegal: y is mutable struct S { int a; char[] b; static S* opCall() { S* ret = new S; s.b = "test"; return ret; } } final S final_s; //final_s exists on the stack or in the global scope final_s.a = 6; //Illegal: s is final final_s.b = "hello"; //ditto final S final_s2 = *S(); //Legal final_s2.b[2] = 'd'; //Legal: final is non-viral final S* s_pointer = new S; //Legal, *(s_pointer) exists on the heap s_pointer.a = 6; //Legal, *(s_pointer) can be mutated through s_pointer s_pionter.b = "hello"; //ditto s_pointer = new S; //Illegal: s_pointer is already assigned final S* s_pointer2 = S(); //Obviously legal const S* const_s_pointer = new S; //Legal y = const_s_pointer.a; //Legal const_s_pointer.a = 5; //Illegal const_s_pointer = S(); //Legal: const_s_pionter can be reassigned invariant S* inv_s_pointer = new S; //Legal y = inv_s_pionter.a; //Legal inv_s_pointer.a = 5; //Illegal inv_s_pointer = S(); //Not sure, but probably illegal: S* points to mutable data, //even though there are no other references to it. How do //invariant pointers work with the static opCall() workaround for //missing struct constructors? Does NRVO deal with this? class C { int a; final S* s_in_c; this() { s_in_c = new S; } //Is it legal to assign final values in constructors? //What about in a static opCall() for structs? void increment_a() { this.a++; } } final C final_c = new C(); final_c = new C(); //Illegal: final_c already assigned. y = final_c.a; //Legal final_c.a = x; //Also legal final_c.increment_a(); //Ditto const C const_c = new C(); const_c = new C(); //Legal: reference const_c can be reassigned const_c.a = y; //Illegal: cannot mutate through const reference const_c.increment_a(); //Legal??? Is the object's "this" reference non-const? invariant C inv_c = new C(); inv_c = new C(); //legal: reference inv_c can be reassigned ivn_c.a = y; //Illegal: cannot mutate through invariant reference inv_c.increment_a(); //Illegal??? The object shouldn't be able to be modified at all, but //how could the compiler catch this?
Mar 19 2007
Tyler Knott wrote:I think I've got this. Is the following right? *final variables can be assigned only once in their lifetime, but are otherwise normal variables (i.e. they *do* have a memory address), except where constant folded by the compiler (this should be completely transparent to the programmer).Correct.*const and invariant only make sense when applied to references, otherwise they are ignored or (preferably) errors.Correct.*const references cannot be used to mutate the data they reference, but the data they reference may be mutated directly or through other non-const, non-invariant references.Correct.*invariant references only reference data that will never be mutated (e.g. final variables).Ambiguously expressed. But I think I see what you mean, e.g. you can take the address of a final int and bind it to an invariant int*, like so: final int x = 42; immutable int* p = &x; // correct*Both const and invariant references can be reassigned unless they are also final references.Correct.*Conversely, when final is applied to the declaration of a reference, only that reference is protected from mutation, not the data it references, unless that reference is also const or invariant.Correct.*Neither const nor invariant references can be cast to non-const or non-invariant references directly.Correct.*The address of any variable or the value of any reference (of compatible type) can be assigned to const references.Correct. (Just like in C++.)*Only the addresses of final variables (I'm sure of this), the direct result of "new" statements (not sure on this one), and the values of other invariant references may be assigned to invariant references.Yes, yes (and more), and yes. New statements can be solved easily by just requiring people to qualify the type created: invariant int* p = new invariant int(42); User-defined types will have a chance to define constructors for invariant objects. Those constructors will have the chance of modifying the object being constructed, but won't be able to alias 'this' and member addresses to modifiable pointers. The deeper problem is with functions that return pointers that could be assigned to either mutable or invariant symbols. For example, array.dup. Take a look: int[] array = [1, 2, 3]; invariant int[] brray = array.dup; // should work invariant int[] crray = array.dup; // should work, too! I am working on a solution for this issue. The problem is rather general. Consider a function char[] readln() that reads a line from the standard input, creating a fresh string each call. That string should be assigned to char[] or invariant char[].*const and invariant are viral (i.e. all references in the data referenced by a const or invariant reference is also const or invariant, respectively, when access through the const or invariant reference)."Transitive." Yes.*final, when applied directly to POD structures (structs and array references), means no members of that structure can be modified after assignment, but is non-viral to references within the POD structure. (Not sure on this.)Correct. "final x" freezes all of x's bits.*Function declarations cannot overloaded based on const or invariant. (Pretty sure on this.)Walter is mildly unconvinced about such overloads' utility, I think they should be allowed without being required. I'll snip your examples, which are correct and also raise a couple of interesting questions that are being worked on. Andrei
Mar 19 2007
On Mon, 19 Mar 2007 22:34:13 -0700, Andrei Alexandrescu (See Website For Email) wrote:Tyler Knott wrote:Can 'const' and 'invariant' apply to structs, especially ones that contain references. struct Foo { char[] s; char c; } const Foo f; // Is this a mistake then? f.s[0] = 'a'; // okay??? f.s = "xyz"; // okay??? f.s = "def".dup; // okay ??? f.s.length = 1; // okay? f.s ~= 'a'; // okay?? f.c = 'a'; // okay??? const Foo somefunc(); f = somefunc; // okay?? Foo someotherfunc(); f = someotherfunc; // okay?? -- Derek (skype: derek.j.parnell) Melbourne, Australia "Justice for David Hicks!" 20/03/2007 4:45:27 PM*const and invariant only make sense when applied to references, otherwise they are ignored or (preferably) errors.Correct.
Mar 19 2007
Derek Parnell wrote:On Mon, 19 Mar 2007 22:34:13 -0700, Andrei Alexandrescu (See Website For Email) wrote:That code is fine. I should have said "const and invariant make sense only when applied to types that are, or contain, references". Sorry.Tyler Knott wrote:Can 'const' and 'invariant' apply to structs, especially ones that contain references. struct Foo { char[] s; char c; } const Foo f; // Is this a mistake then?*const and invariant only make sense when applied to references, otherwise they are ignored or (preferably) errors.Correct.f.s[0] = 'a'; // okay???No.f.s = "xyz"; // okay???Yes.f.s = "def".dup; // okay ???Yes.f.s.length = 1; // okay?Yes.f.s ~= 'a'; // okay??Yes.f.c = 'a'; // okay???Yes.const Foo somefunc(); f = somefunc; // okay??Yes.Foo someotherfunc(); f = someotherfunc; // okay??Yes. Non-const transforms into const no problem. Andrei
Mar 19 2007
Andrei Alexandrescu (See Website For Email) wrote:Derek Parnell wrote:What?? If f is 'const', how are any of those "f.s =" assignments allowed? -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DOn Mon, 19 Mar 2007 22:34:13 -0700, Andrei Alexandrescu (See Website For Email) wrote:That code is fine. I should have said "const and invariant make sense only when applied to types that are, or contain, references". Sorry.Tyler Knott wrote:Can 'const' and 'invariant' apply to structs, especially ones that contain references. struct Foo { char[] s; char c; } const Foo f; // Is this a mistake then?*const and invariant only make sense when applied to references, otherwise they are ignored or (preferably) errors.Correct.f.s[0] = 'a'; // okay???No.f.s = "xyz"; // okay???Yes.f.s = "def".dup; // okay ???Yes.f.s.length = 1; // okay?Yes.f.s ~= 'a'; // okay??Yes.f.c = 'a'; // okay???Yes.const Foo somefunc(); f = somefunc; // okay??Yes.Foo someotherfunc(); f = someotherfunc; // okay??Yes. Non-const transforms into const no problem. Andrei
Mar 20 2007
Bruno Medeiros wrote:What?? If f is 'const', how are any of those "f.s =" assignments allowed?Because f is a POD (Plain Old Data) structure and not a reference you can modify the data in the structure, but because it's declared const you can't modify any data referenced. If you want f.s to be unassignable then declare f to be final Foo, though you can then modify the data referenced by f.s so f.s[0] = 'a'; becomes legal. For example: struct Foo { char[] s = "hello"; char c; } const Foo const_foo; final Foo final_foo; final const Foo const_final_foo; const Foo* const_foo_pointer = new Foo; const_foo.s = "test"; //Legal: data directly modified (const only invalidates modification through references) final_foo.s = "test"; //Illegal: cannot modify data in final variables const_final_foo.s = "test"; //Illegal: cannot modify data in final variables const_foo_pointer.s = "test"; //Illegal: cannot modify data through const references const_foo.s[0] = 'a'; //Illegal: cannot modify data through const references //(const declaration is transitive to const_foo.s reference) final_foo.s[0] = 'a'; //Legal: you're not modifying any data in final_foo, only data referenced by it const_final_foo.s[0] = 'a'; //Illegal: cannot modify data through const references const_foo_pointer.s[0] = 'a'; //Illegal: cannot modify data through const references
Mar 20 2007
Tyler Knott wrote:Bruno Medeiros wrote:Duh, of course. I misread and was thinking Foo was a class and not a struct. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DWhat?? If f is 'const', how are any of those "f.s =" assignments allowed?Because f is a POD (Plain Old Data) structure and not a reference you can modify the data in the structure, but because it's declared const you can't modify any data referenced. If you want f.s to be unassignable then declare f to be final Foo, though you can then modify the data referenced by f.s so f.s[0] = 'a'; becomes legal. For example: struct Foo { char[] s = "hello"; char c; }
Mar 21 2007