digitalmars.D - Why can't we define re-assignable const reference variable?
- none (37/37) Feb 16 2008 Why can't we define re-assignable const reference variable?
- Janice Caron (5/6) Feb 16 2008 This has been covered so many times before, but in summary, allowing
- Christopher Wright (3/8) Feb 16 2008 What's the difference (save polymorphism) between a pointer to a struct
- Janice Caron (3/5) Feb 16 2008 I don't understand the question.
- Christopher Wright (11/18) Feb 16 2008 Well, chalk has a significantly higher calcium content and has usually
- Janice Caron (12/24) Feb 16 2008 Yes there is.
- Christopher Wright (7/23) Feb 16 2008 generic programming != type system
- Janice Caron (7/8) Feb 16 2008 I can't argue with that! :-) Perhaps I should have said, it will break
- Robert Fraser (14/23) Feb 17 2008 D already has types that break generic programming. Static arrays, anyon...
- Janice Caron (2/7) Feb 17 2008 Isn't that rather because modifying s1.x modifies s1?
- Robert Fraser (2/11) Feb 17 2008 Technically, yes. But what I was (and still am) campaigning for is synta...
- Christopher Wright (10/22) Feb 17 2008 Oh dear GOD yes. I'm doing an assertions library right now (cooked it up...
- none (20/26) Feb 16 2008 I don't understand why it will break the type system; in any case, even ...
- none (5/8) Feb 16 2008 const C* b;
- Christopher Wright (12/20) Feb 16 2008 From Walter's perspective, there are a few choices:
- none (8/14) Feb 16 2008 Actually we can rebind already: this is legal code accepted by the DMD c...
- Christopher Wright (10/28) Feb 17 2008 That doesn't really work. For purposes of const, it's as if you wrote:
- Sergey Gromov (17/44) Feb 16 2008 This is not how the things currently are. Actually it's like this:
- Janice Caron (3/5) Feb 16 2008 ???
- Sergey Gromov (8/15) Feb 17 2008 But it wouldn't mean mutable reference to const data. This /looks/ like...
- Janice Caron (19/36) Feb 17 2008 Of course not. That would be impossible.
- Sean Reque (1/8) Feb 17 2008 This argument is completely pointless, because in C++ you don't have ref...
- Sergey Gromov (16/59) Feb 17 2008 You can't have a mutable reference to mutable data in C++, either. D
- Janice Caron (8/9) Feb 17 2008 That's just not getting it. x has type const(C), therefore x is const.
- Derek Parnell (38/40) Feb 18 2008 Of course you can. I do it all the time. But maybe I don't understand wh...
- Denton Cockburn (2/32) Feb 18 2008 That doesn't compile in 2.010
- Derek Parnell (9/34) Feb 18 2008 Damn! You're right. I was using an earlier version of D. However, if you
- Sergey Gromov (42/46) Feb 18 2008 One can safely assume that a variable x of type int with a value 4 in it...
- Janice Caron (9/11) Feb 18 2008 Not unless you've redefined the word reference.
- Robert Fraser (2/16) Feb 18 2008 I _think_ he was trying to describe it from a logical, rather than imple...
- Sergey Gromov (4/25) Feb 18 2008 You're absolutely correct.
- Sergey Gromov (18/32) Feb 18 2008 I'm talking from the standpoint of generalization which you so much care...
- Janice Caron (20/22) Feb 18 2008 Well sure, but if you use a word to mean one thing, and I understand
- Sean Reque (1/8) Feb 18 2008 Well if Walter wants people to use his language, he needs to do some bet...
- Derek Parnell (8/9) Feb 18 2008 I'm starting to suspect that in the effort to make the const system simp...
- Bill Baxter (4/9) Feb 18 2008 I'm ok with simplistic as long as simple, common things remain simple.
- Janice Caron (2/3) Feb 18 2008 I've been using it for a while now, and on the whole I find it very
- Derek Parnell (6/10) Feb 19 2008 So long as one isn't trying to do things that Walter disagrees with.
- Walter Bright (12/18) Feb 19 2008 That's a good point, and a good reason why:
- Derek Parnell (18/30) Feb 19 2008 Ok given this position and that 'string' is 'invariant(char)[]' then
- Janice Caron (11/16) Feb 19 2008 No, s is an array of immutable chars. Put another way, as I am sure
- Derek Parnell (8/24) Feb 19 2008 I took it that he was saying that 'c' and 'i' are references.
- Steven Schveighoffer (51/68) Feb 19 2008 So please explain this:
- Janice Caron (12/17) Feb 19 2008 Simple. If you wanted the output to be 2 2 2 2 then the second
- Steven Schveighoffer (10/29) Feb 19 2008 You missed the point completely. I'm not asking to find bugs in my code...
- Sergey Gromov (18/24) Feb 19 2008 A reference refers to data which is outside of the reference's body.
- Walter Bright (4/32) Feb 19 2008 That is only a small part of why D classes are reference types. The
- Sergey Gromov (10/46) Feb 20 2008 My argument was not about references vs values but about references vs
- Janice Caron (35/39) Feb 16 2008 I think you mistyped. (1) means "b is a const pointer to mutable
- none (13/22) Feb 17 2008 I just want to make it clear again, nobody has what you called 'misconce...
- Janice Caron (5/8) Feb 17 2008 I disagree. I say a pointer is a pointer is a pointer, and that a
- Matti Niemenmaa (20/27) Feb 17 2008 The difference is that in C++, 'new C' results in a C*, whereas in D it ...
- Janice Caron (10/12) Feb 17 2008 OK, I see that.
- =?UTF-8?B?U8O2bmtlIEx1ZHdpZw==?= (10/25) Feb 17 2008 Show me how I can maintain a simple map of class instances, which I get ...
- Janice Caron (6/12) Feb 17 2008 So change it to
- =?UTF-8?B?U8O2bmtlIEx1ZHdpZw==?= (21/43) Feb 18 2008 Since C is a class, const(C)* will mean a mutable pointer to a const cla...
- =?UTF-8?B?U8O2bmtlIEx1ZHdpZw==?= (2/2) Feb 18 2008 Sorry, the "new S(someinst)" syntax will not work, of course.
- Robert Fraser (3/9) Feb 18 2008 I don't feel good about sacrificing performance for something that I've ...
- Sean Reque (2/14) Feb 17 2008 Having a const class with mutable reference makes the language much much...
- Sean Reque (12/18) Feb 18 2008 The saddest part of this is it actually worked this way at least up thro...
- Craig Black (8/31) Feb 18 2008 When the latest const system became final, I was a little disappointed, ...
- Steven Schveighoffer (75/78) Feb 19 2008 The problem here, none (is that your real name?), is that Walter has tri...
- Yigal Chripun (64/64) Feb 19 2008 here's my random thought on the subject (just wanted to throw those in
- Sergey Gromov (7/15) Feb 19 2008 Please, why invent new syntax ?
- Steven Schveighoffer (13/17) Feb 19 2008 Yes, this is one of the trials of Walter to see if he could get tail-con...
- Sergey Gromov (16/38) Feb 20 2008 If you create a generic algorithm which works with T, and declare
- Janice Caron (29/34) Feb 20 2008 Sergey, there may well be merit in the idea of having some form of
- Sergey Gromov (26/55) Feb 20 2008 Pointers ruin my beautiful theory. :-)
- Janice Caron (23/28) Feb 20 2008 Not good enough. Everything inside the /brackets/ must be const.
- Sergey Gromov (41/73) Feb 20 2008 I am a newbie. I want consistency in the language. This is what
- Janice Caron (4/6) Feb 20 2008 That was a typo. Allow me to correct myself.
- Janice Caron (39/63) Feb 20 2008 Yuk! Fortunately, I just don't believe Walter will go for that.
- Sergey Gromov (17/55) Feb 20 2008 Modifying a slice which points i-dont-know-where feels unsafe to me. I
- Janice Caron (10/23) Feb 20 2008 string s = "hello world";
- Sergey Gromov (10/38) Feb 21 2008 This is Ok. It's changing the .length directly which I don't like, and
- Janice Caron (16/19) Feb 21 2008 It's always safe, and it's always predictable. It's just not very useful...
- Frits van Bommel (5/15) Feb 21 2008 Well, there's one difference between what happens there and realloc();
- Robert Fraser (3/46) Feb 20 2008 I wasn't aware of tat syntax. Please retract all comments I made in this...
- Steven Schveighoffer (5/51) Feb 20 2008 Hm... maybe true, but this is not the supported syntax for the current o...
- Steven Schveighoffer (8/47) Feb 20 2008 Sergey, I am not arguing that the functionality that you wish to have i...
- Sergey Gromov (7/35) Feb 20 2008 The traditional usage of parentheses is this: foo(x). This means that a...
- Janice Caron (5/9) Feb 20 2008 Happy to.
- Sergey Gromov (16/27) Feb 20 2008 I see, thank you. It's really natural to think of const() as of a type-
- Janice Caron (13/16) Feb 20 2008 No. Consider
- Yigal Chripun (18/37) Feb 20 2008 what if we separate const into two keywords?
- Janice Caron (10/11) Feb 20 2008 Wouldn't the word "const" be superfluous in that example, since
- Yigal Chripun (16/30) Feb 20 2008 As I've already said: it's only a start of an idea and should be further
- Yigal Chripun (43/81) Mar 06 2008 after thinking about the above here are my thoughts:
- Simen Kjaeraas (21/105) Mar 08 2008 onst =
- Yigal Chripun (15/113) Mar 08 2008 why not? I only used const to simplify. you can add variant with the
- Janice Caron (20/22) Mar 08 2008 The bad news is, that would also disallow
- Yigal Chripun (19/44) Mar 09 2008 since all programming languages are Turing complete you can write code
- Steven Schveighoffer (19/53) Feb 20 2008 That is the usage I am referring to. I'll spell it out in English:
- Sergey Gromov (12/21) Feb 20 2008 At least, now I understand why we can't understand each other.
- Steven Schveighoffer (14/35) Feb 20 2008 C is a class reference. There is no way to express the type of the clas...
Why can't we define re-assignable const reference variable? i.e. the variable can be re-bind, but it's allowed to change the object it points to: This is such a pain to port D 1.0 code to 2.0, e.g. I have some code in D 1.0 like this: ======================== B b1, b2; b1 = new B(); b2 = new B(); B b; b = b1; b.MemberFunc(); // later change to const member function b = b2; b.anotherMemberFunc(); // later change to const member function ======================== When porting to D 2.0, some of the method of class B is changed to const member function, and I want to make my intention clear, so I changed 'B b', to be 'const B b'. Now the trouble is, b can only be init-ed once, but cannot be re-assigned. I know I can use pointer to achieve what I want: ======================== B b1, b2; b1 = new B(); b2 = new B(); const(B)* b; // type change b = &b1; // additional change b.constMemberFunc(); b = &b2; // additional change b.anotherConstMemberFunc(); ======================== Then I have to change the code in multiple places; and the other problem is that I will have to use pointers most of the time in my code. So why can't we have both (just as in C++): ======================== const B b; // b cannot be re-bind, and the object cannot be modified B const b; // b can be re-bind, but the object cannot be modified ========================
Feb 16 2008
On 16/02/2008, none <z gg.com> wrote:So why can't we have both (just as in C++):This has been covered so many times before, but in summary, allowing that would completely break the type system. But I just want to clear up one misconception. You /cannot/ do that in C++. References in C++ are /never/ rebindable.
Feb 16 2008
Janice Caron wrote:On 16/02/2008, none <z gg.com> wrote:What's the difference (save polymorphism) between a pointer to a struct and a reference to an object?So why can't we have both (just as in C++):This has been covered so many times before, but in summary, allowing that would completely break the type system.
Feb 16 2008
On 16/02/2008, Christopher Wright <dhasenan gmail.com> wrote:What's the difference (save polymorphism) between a pointer to a struct and a reference to an object?I don't understand the question. What's the difference between chalk and cheese? What are you getting at?
Feb 16 2008
Janice Caron wrote:On 16/02/2008, Christopher Wright <dhasenan gmail.com> wrote:Well, chalk has a significantly higher calcium content and has usually not gone through a cow. In C++, there's no difference between the two. In D, the difference appears to be that there is no syntax separate the reference from the object, besides an ugly cast. I've never heard any explanation of how reassignable const objects would break the type system, and it seems to me that, if they would, then you shouldn't be able to do: struct Foo{} const(Foo)* fptr;What's the difference (save polymorphism) between a pointer to a struct and a reference to an object?I don't understand the question. What's the difference between chalk and cheese? What are you getting at?
Feb 16 2008
On 16/02/2008, Christopher Wright <dhasenan gmail.com> wrote:Yes there is. S * p = whatever; S & r = whatever; p can be rebound. r can't.In C++, there's no difference between the two.What's the difference (save polymorphism) between a pointer to a struct and a reference to an object?In D, the difference appears to be that there is no syntax separate the reference from the object, besides an ugly cast.And nor is there in C++. You cannot modify r. There is no way to get at r. You can't even take the address of r. C++ prohibits you, and no one's ever complained that that's a problem. If you want to rebind, you use a pointer.I've never heard any explanation of how reassignable const objects would break the type system,Because you'd need a brand new syntax to do it, and whatever syntax you chose, it would break generic programming.and it seems to me that, if they would, then you shouldn't be able to do: struct Foo{} const(Foo)* fptr;There's no problem with that. fptr is a pointer, not a reference.
Feb 16 2008
Janice Caron wrote:On 16/02/2008, Christopher Wright <dhasenan gmail.com> wrote:Hm. Perhaps I should learn c++ before talking about it.Yes there is. S * p = whatever; S & r = whatever; p can be rebound. r can't.In C++, there's no difference between the two.What's the difference (save polymorphism) between a pointer to a struct and a reference to an object?generic programming != type system I forgot about that argument, though. Thanks for reminding me. The solution, of course, is first-class references for everything, which Walter isn't willing to do. In almost every circumstance, it'd be duplicated functionality.I've never heard any explanation of how reassignable const objects would break the type system,Because you'd need a brand new syntax to do it, and whatever syntax you chose, it would break generic programming.
Feb 16 2008
On 16/02/2008, Christopher Wright <dhasenan gmail.com> wrote:generic programming != type systemI can't argue with that! :-) Perhaps I should have said, it will break /either/ generic programming /or/ the type system. I suppose I was thinking that if you have new syntax, and you want to keep generic programming, then somehow you must force the new syntax to work for all types, and /that/ breaks the type system, but I guess I was probably thinking too far ahead there. :-)
Feb 16 2008
Janice Caron Wrote:On 16/02/2008, Christopher Wright <dhasenan gmail.com> wrote:D already has types that break generic programming. Static arrays, anyone? One thing I was arguing for before the const system was implemented as it is now is for structs to act as similarly to classes as possible, only stack allocated. So while there was still a question of "head-const" and "tail-const", a "tail-const" struct would be the same as a "tail-const" class: that is, the reference would be rebindable, but members would not be. For example: struct S { int x; } class C { int x; } tailconst(S) s1; tailconst(S) s2; tailconst(C) c1 = new C(); tailconst(C) c2 = new C(); s1 = s2; // Okay c1 = c2; // Okay s1.x = 5; // Not okay c1.x = 5; // Not okay When I proposed this, NOBODY agreed with me (that is, everybody who responded wanted structs/classes to act differently for generic programming purposes).generic programming != type systemI can't argue with that! :-) Perhaps I should have said, it will break /either/ generic programming /or/ the type system. I suppose I was thinking that if you have new syntax, and you want to keep generic programming, then somehow you must force the new syntax to work for all types, and /that/ breaks the type system, but I guess I was probably thinking too far ahead there. :-)
Feb 17 2008
On 17/02/2008, Robert Fraser <fraserofthenight gmail.coim> wrote:s1 = s2; // Okay c1 = c2; // Okay s1.x = 5; // Not okay c1.x = 5; // Not okay When I proposed this, NOBODY agreed with me (that is, everybody who responded wanted structs/classes to act differently for generic programming purposes).Isn't that rather because modifying s1.x modifies s1?
Feb 17 2008
Janice Caron Wrote:On 17/02/2008, Robert Fraser <fraserofthenight gmail.coim> wrote:Technically, yes. But what I was (and still am) campaigning for is syntax changes where by "struct S" can be changed to "class X" and no client code will be broken at all. Structs/classes should behave differently from an implementation perspective (not like C++), so for example structs are data types/stack allocated and don't support inheritance, but they should be usable in roughly the same way by clients. This removes the decision from the API for most purposes.s1 = s2; // Okay c1 = c2; // Okay s1.x = 5; // Not okay c1.x = 5; // Not okay When I proposed this, NOBODY agreed with me (that is, everybody who responded wanted structs/classes to act differently for generic programming purposes).Isn't that rather because modifying s1.x modifies s1?
Feb 17 2008
Robert Fraser wrote:Janice Caron Wrote:Oh dear GOD yes. I'm doing an assertions library right now (cooked it up over the past couple days because I got tired of writing assert (something, "salient description here")) and strings are absolutely KILLING me. I want to support Tango collections for list constraints, but I can't instantiate it with a static array. I can write some ugly templates to make it go away, but it's just really annoying. And then I think sameAs constraints won't work right. If strings were dynamic arrays, all my troubles would disappear.On 16/02/2008, Christopher Wright <dhasenan gmail.com> wrote:D already has types that break generic programming. Static arrays, anyone?generic programming != type systemI can't argue with that! :-) Perhaps I should have said, it will break /either/ generic programming /or/ the type system. I suppose I was thinking that if you have new syntax, and you want to keep generic programming, then somehow you must force the new syntax to work for all types, and /that/ breaks the type system, but I guess I was probably thinking too far ahead there. :-)
Feb 17 2008
== Quote from Janice Caron (caron800 googlemail.com)'s articleOn 16/02/2008, none <z gg.com> wrote:I don't understand why it will break the type system; in any case, even without it (as we do now), I can always get around it by using D pointers: const(B)* b; // type change b = &b1; // rebind b = &b2; // rebind It's just so inconvenient, that's why I suggest allow define re-assignable const reference variable.So why can't we have both (just as in C++):This has been covered so many times before, but in summary, allowing that would completely break the type system.But I just want to clear up one misconception. You /cannot/ do that in C++. References in C++ are /never/ rebindable.That's a terminology issue, to make it clear: class C {} D C++ ========================= =========================== reference: C c = new C(); pointer: C *c = new C(); pointer: C* cp = &c; ptr-to-ptr: C **cp = &c; What I mean is in C++, you can define 2 different kinds of C++ pointers: const C* b; // b cannot be re-bind, and the object cannot be modified C* const b; // b can be re-bind, but the object cannot be modified So in D we should be able to define 2 different kinds of D reference: const C b; // b cannot be re-bind, and the object cannot be modified C const b; // b can be re-bind, but the object cannot be modified
Feb 16 2008
Sorry in C++, it should beWhat I mean is in C++, you can define 2 different kinds of C++ pointers: const C* b; // b cannot be re-bind, and the object cannot be modifiedC* const b;C* const b; // b can be re-bind, but the object cannot be modifiedconst C* b; and: const C* const b; // both pointer, and data are const.
Feb 16 2008
none wrote:== Quote from Janice Caron (caron800 googlemail.com)'s articleFrom Walter's perspective, there are a few choices: - First-class references. A large language feature to solve a small problem. - Do nothing. - Have Andrei cook up a library solution. For that last, you can't simply put a struct around it and go on your merry way. The closest you can reasonably come is: struct Tailconst(T) { T t; void opAssign(T value) { t = value; } // insert method and operator forwarding here }On 16/02/2008, none <z gg.com> wrote:I don't understand why it will break the type system; in any case, even without it (as we do now), I can always get around it by using D pointers:So why can't we have both (just as in C++):This has been covered so many times before, but in summary, allowing that would completely break the type system.
Feb 16 2008
Actually we can rebind already: this is legal code accepted by the DMD compiler for (i = n; i-- > 0; ) { const B b = getConstB(i); // are we rebind here n-times already? b.doSomething(); } // the trouble is I cannot use the last 'b' i.e. getConstB(0), // anymore, it will be out of scope b.doSomethingElse();(as we do now), I can always get around it by using D pointers: const(B)* b; // type change b = &b1; // rebind b = &b2; // rebind It's just so inconvenient, that's why I suggest allow define re-assignable const reference variable.
Feb 16 2008
none wrote:Actually we can rebind already: this is legal code accepted by the DMD compiler for (i = n; i-- > 0; ) { const B b = getConstB(i); // are we rebind here n-times already? b.doSomething(); }That doesn't really work. For purposes of const, it's as if you wrote: void loopBody (int i) { const B b = getConstB(i); b.doSomething(); } for (i = n; i > 0; i--) { loopBody(i); }// the trouble is I cannot use the last 'b' i.e. getConstB(0), // anymore, it will be out of scope b.doSomethingElse();Then there's no way to say you don't want to be able to rebind it.(as we do now), I can always get around it by using D pointers: const(B)* b; // type change b = &b1; // rebind b = &b2; // rebind It's just so inconvenient, that's why I suggest allow define re-assignable const reference variable.
Feb 17 2008
none <z gg.com> wrote:== Quote from Janice Caron (caron800 googlemail.com)'s articleThis is not how the things currently are. Actually it's like this: class C {} struct S {} D C++ ========================= =========================== reference: C c = new C(); pointer: C *c = new C(); pointer: C* cp = &c; pointer: C *cp = c; value: S s = {}; value: S s = {}; pointer: S* sp = &s; pointer: S *sp = &s; no equiv. reference: C &cr = *c; no equiv. reference: C &sr = s; So it's really strange that you can't declare const(C) x; All the syntax is here already. -- SnakEOn 16/02/2008, none <z gg.com> wrote:I don't understand why it will break the type system; in any case, even without it (as we do now), I can always get around it by using D pointers: const(B)* b; // type change b = &b1; // rebind b = &b2; // rebind It's just so inconvenient, that's why I suggest allow define re-assignable const reference variable.So why can't we have both (just as in C++):This has been covered so many times before, but in summary, allowing that would completely break the type system.But I just want to clear up one misconception. You /cannot/ do that in C++. References in C++ are /never/ rebindable.That's a terminology issue, to make it clear: class C {} D C++ ========================= =========================== reference: C c = new C(); pointer: C *c = new C(); pointer: C* cp = &c; ptr-to-ptr: C **cp = &c;
Feb 16 2008
On 17/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:So it's really strange that you can't declare const(C) x;??? You can!
Feb 16 2008
Janice Caron <caron800 googlemail.com> wrote:On 17/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:But it wouldn't mean mutable reference to const data. This /looks/ like const only affecting C, but, in fact, constness is expanded over the whole declaration. I.e. the syntax for declaring reference to const is already in the language, the question is, why it's not in the type system. -- SnakESo it's really strange that you can't declare const(C) x;??? You can!
Feb 17 2008
On 17/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:Janice Caron <caron800 googlemail.com> wrote:Of course not. That would be impossible. You cannot have a mutable reference to const data in C++, so what's the big deal? The best you can achieve in C++ is a mutable /pointer/ to const data, and that is also allowed in D.On 17/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:But it wouldn't mean mutable reference to const data.So it's really strange that you can't declare const(C) x;??? You can!This /looks/ like const only affecting Cconst is transitive, so it affects C, and everything referenced by C. It declares the four-byte reference on the stack that is C, to be const, and since const is transitive, that makes the instance of C's data on the heap const, and everything referenced therefrom.but, in fact, constness is expanded over the whole declaration.Of course. Everything in the brackets is const. That's what's brackets are for - precedence. C is in the brackets; C is const.I.e. the syntax for declaring reference to const is already in the language,You're going to have to clarify that, I'm afraid, as I don't understand. Are you referring to the function parameter syntax ref const(C) c ? In this case, c is indeed rebindable, but only because an extra level of indirection has been silently added.the question is, why it's not in the type system.I don't agree that that's even a reasonable question, because there is /not/ a syntax for "mutable reference to constant data" (not counting function parameters).
Feb 17 2008
Of course not. That would be impossible. You cannot have a mutable reference to const data in C++, so what's the big deal? The best you can achieve in C++ is a mutable /pointer/ to const data, and that is also allowed in D.This argument is completely pointless, because in C++ you don't have references at all, at least not in the same sense as references are in most every other Scheme, Javascript, etc. In most languages, including D, references are basically there to replace pointers as a much safer and more syntactically pleasing alternative when the full power of pointers isn't needed or desired (segmentation fault, anyone?). Therefore, references in D should have the same flexibility as a pointer would. But right now references behave like pointers in terms of assignment, but const references do NOT behave like const pointers in terms of assignment, and that simply should not be.
Feb 17 2008
Janice Caron <caron800 googlemail.com> wrote:On 17/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:You can't have a mutable reference to mutable data in C++, either. D allows that. Why allow one but deny the other, I don't get it.Janice Caron <caron800 googlemail.com> wrote:Of course not. That would be impossible. You cannot have a mutable reference to const data in C++, so what's the big deal? The best you can achieve in C++ is a mutable /pointer/ to const data, and that is also allowed in D.On 17/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:But it wouldn't mean mutable reference to const data.So it's really strange that you can't declare const(C) x;You can!Yes, the C and everything below is const. But why x ? It doesnt belong to C, it's in my function scope. It's not transitiviness that bothers me, but backward transitiviness.This /looks/ like const only affecting Cconst is transitive, so it affects C, and everything referenced by C. It declares the four-byte reference on the stack that is C, to be const, and since const is transitive, that makes the instance of C's data on the heap const, and everything referenced therefrom.But x is outside brackets ! Why is it const, too ?but, in fact, constness is expanded over the whole declaration.Of course. Everything in the brackets is const. That's what's brackets are for - precedence. C is in the brackets; C is const.When I write, "const(C) x;", I mean, "C is const but x is not." This is semantically correct because the assignment operator works with the reference directly when an object of the same type is assigned. It's in the language specs. There is no problem for the assignment to check at compile time if the x itself is const or not.I.e. the syntax for declaring reference to const is already in the language,You're going to have to clarify that, I'm afraid, as I don't understand. Are you referring to the function parameter syntax ref const(C) c ? In this case, c is indeed rebindable, but only because an extra level of indirection has been silently added.It could've been. You wouldn't need to change the language syntax if you wanted to add one. -- SnakEthe question is, why it's not in the type system.I don't agree that that's even a reasonable question, because there is /not/ a syntax for "mutable reference to constant data" (not counting function parameters).
Feb 17 2008
On 18/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:When I write, "const(C) x;", I mean, "C is const but x is not."That's just not getting it. x has type const(C), therefore x is const. I say again, there is no way to express "mutable reference to const data" in D, and any method you come up with to allow that would be (a) incredibly confusing, and (b) would break generic programming and/or the type system. And ... you never need to do that anyway. There's always a different way of writing the code.
Feb 17 2008
On Mon, 18 Feb 2008 07:12:08 +0000, Janice Caron wrote:I say again, there is no way to express "mutable reference to const data" in DOf course you can. I do it all the time. But maybe I don't understand what you are saying ;-) import std.stdio; class Foo { const string _me; this(string name) { _me = name; writefln("Creating %s", _me); } } void main() { const(Foo) f; // A mutable reference to const data. const(Foo) a = new Foo("one"); const(Foo) b = new Foo("two"); const(Foo) c = new Foo("three"); f = a; f = b; f = c; writefln("%s", f._me); } What I can't get D to do easily is declare a const reference to mutable data. Yes, I know there are ways to trick D to get around this but its not as nice as just letting the programmer achieve their goals with simpler, more intuitive syntax. eg.. const nonconst(Foo) f; // 'f' is const but it's data is not. And I know the argument "But what purpose what that really serve?". The answer to that is "doing it another way is more complex". But anyhow, I know its not going to happen so my part in the discussion can end here. -- Derek (skype: derek.j.parnell) Melbourne, Australia 18/02/2008 7:04:36 PM
Feb 18 2008
On Mon, 18 Feb 2008 19:36:31 +1100, Derek Parnell wrote:On Mon, 18 Feb 2008 07:12:08 +0000, Janice Caron wrote:That doesn't compile in 2.010I say again, there is no way to express "mutable reference to const data" in DOf course you can. I do it all the time. But maybe I don't understand what you are saying ;-) import std.stdio; class Foo { const string _me; this(string name) { _me = name; writefln("Creating %s", _me); } } void main() { const(Foo) f; // A mutable reference to const data. const(Foo) a = new Foo("one"); const(Foo) b = new Foo("two"); const(Foo) c = new Foo("three"); f = a; f = b; f = c; writefln("%s", f._me); }
Feb 18 2008
On Mon, 18 Feb 2008 08:39:58 -0500, Denton Cockburn wrote:On Mon, 18 Feb 2008 19:36:31 +1100, Derek Parnell wrote:Damn! You're right. I was using an earlier version of D. However, if you replace 'const(Foo)' with 'const(char)[]' is does compile. Which means that a dynamic array, which is a reference type, can be mutable even though its data is not. -- Derek Parnell Melbourne, Australia skype: derek.j.parnellimport std.stdio; class Foo { const string _me; this(string name) { _me = name; writefln("Creating %s", _me); } } void main() { const(Foo) f; // A mutable reference to const data. const(Foo) a = new Foo("one"); const(Foo) b = new Foo("two"); const(Foo) c = new Foo("three"); f = a; f = b; f = c; writefln("%s", f._me); }That doesn't compile in 2.010
Feb 18 2008
Janice Caron <caron800 googlemail.com> wrote:I say again, there is no way to express "mutable reference to const data" in D, and any method you come up with to allow that would be (a) incredibly confusing, and (b) would break generic programming and/or the type system.One can safely assume that a variable x of type int with a value 4 in it is a mutable reference to an object 4 of type invariant(int). That is, all variables of primitive types in D (as well as in other languages) are either mutable or immutable references to invariant objects. Class type variables in D are either mutable references to mutable objects, or immutable references to immutable objects. Pointers are either mutable or immutable references to either mutable or immutable objects, except head-const variant. Struct type variables are exactly like primitives if struct doesn't contain references somewhere. I like to call them PODs. Modifying a struct is generalised as replacing a reference to one immutable set of data with a reference to another immutable set of data, exactly as it is with primitive types. Non-POD structs cannot be generalised as references. Hence all the problems with them. So, here is a table summarizing what current D constructs can do: ref tgt Primitive/POD: var inv const inv inv inv Class: var var const const inv inv Pointer: var var var const var inv const const const inv inv inv The left column is a reference type, the right column is a type of referenced object. As you can see, the most generic type is pointer. That's why you suggest using it here and there. But it's not the D way. In D, the class reference should be the most generic. It should be safe to assume everything is reference when you write a template. The mutable references to const objects are not breaking generic programming, but aiding it. -- SnakE
Feb 18 2008
On 18/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:One can safely assume that a variable x of type int with a value 4 in it is a mutable reference to an object 4 of type invariant(int).Not unless you've redefined the word reference. At the ABI level, a reference is identical to a pointer. It occupies four bytes of space (eight on a 64 bit machine), and those four bytes contain an address. The difference between a reference and a pointer occurs at the syntax level, not the ABI level. What you've described there is not a reference at all - it's an int. A reference to an int would occupy eight bytes of memory (four for the reference, and four more for the int).
Feb 18 2008
Janice Caron Wrote:On 18/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:I _think_ he was trying to describe it from a logical, rather than implementation standpoint. Logically, x "refers" (using the English term, not the programming term, mind you) to 4. 4 can't be changed (you can't say 4 = 7), but x can be.One can safely assume that a variable x of type int with a value 4 in it is a mutable reference to an object 4 of type invariant(int).Not unless you've redefined the word reference. At the ABI level, a reference is identical to a pointer. It occupies four bytes of space (eight on a 64 bit machine), and those four bytes contain an address. The difference between a reference and a pointer occurs at the syntax level, not the ABI level. What you've described there is not a reference at all - it's an int. A reference to an int would occupy eight bytes of memory (four for the reference, and four more for the int).
Feb 18 2008
Robert Fraser <fraserofthenight gmail.coim> wrote:Janice Caron Wrote:You're absolutely correct. -- SnakEOn 18/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:I _think_ he was trying to describe it from a logical, rather than implementation standpoint. Logically, x "refers" (using the English term, not the programming term, mind you) to 4. 4 can't be changed (you can't say 4 = 7), but x can be.One can safely assume that a variable x of type int with a value 4 in it is a mutable reference to an object 4 of type invariant(int).Not unless you've redefined the word reference. At the ABI level, a reference is identical to a pointer. It occupies four bytes of space (eight on a 64 bit machine), and those four bytes contain an address. The difference between a reference and a pointer occurs at the syntax level, not the ABI level. What you've described there is not a reference at all - it's an int. A reference to an int would occupy eight bytes of memory (four for the reference, and four more for the int).
Feb 18 2008
Janice Caron <caron800 googlemail.com> wrote:On 18/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:I'm talking from the standpoint of generalization which you so much care about. When I generalize, I don't care how things are implemented. It's behaviour that matters. If I create an algorithm that uses references to invariant data, then it will work with anything that /behaves/ like such references. Even if they are actually ints passed by value. Imagine a language with only one class of objects, that is, objects passed by reference. Integer numbers are invariant objects of type int, and an integer variable is a reference to an invariant object of type int. Since the int objects are immutable, a compiler of this language can safely optimize the code and keep the int object values in place of references. This is what D does. It's an implementation detail. It's an optimization which just happened to end up in language specs. This optimization is so common that it's probably hard to believe that it's only an efficient implementation of a generic concept of a reference. -- SnakEOne can safely assume that a variable x of type int with a value 4 in it is a mutable reference to an object 4 of type invariant(int).Not unless you've redefined the word reference. At the ABI level, a reference is identical to a pointer. It occupies four bytes of space (eight on a 64 bit machine), and those four bytes contain an address. The difference between a reference and a pointer occurs at the syntax level, not the ABI level. What you've described there is not a reference at all - it's an int. A reference to an int would occupy eight bytes of memory (four for the reference, and four more for the int).
Feb 18 2008
On 18/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:I'm talking from the standpoint of generalization which you so much care about.Well sure, but if you use a word to mean one thing, and I understand it to mean something else, then we are not communicating. Communication has failed, and we are not understanding each other. Now, I'm no longer confident that I've got anything you've said, or that you've got anything I've said. We may have been talking at cross-purposes this whole thread. When I discuss generalization, I need to be able to say/think "this is how it's implemented for pointers; this is how it's implemented for references; this is how...", and so on. If you redefine all the words, then it just means we'll have to invent new ones in order to talk properly about the ABI. Ah well. No matter. :-) For what it's worth, I was arguing exactly what you are arguing now (that it should be allowable to modify the class reference of a const class), several weeks back. But Walter patiently explained why it was not a good idea, and his arguments were sound, so I got convinced. In other words, this isn't a new argument - you might want to check out some of that history (although I'm not sure I can advise on what to search for - "const" would probably yeild rather too many hits!)
Feb 18 2008
For what it's worth, I was arguing exactly what you are arguing now (that it should be allowable to modify the class reference of a const class), several weeks back. But Walter patiently explained why it was not a good idea, and his arguments were sound, so I got convinced. In other words, this isn't a new argument - you might want to check out some of that history (although I'm not sure I can advise on what to search for - "const" would probably yeild rather too many hits!)Well if Walter wants people to use his language, he needs to do some better convincing. I looked around and couldn't find anything searching around for 15 minutes. I liked D when I first learned about it, but I keep finding out things that were "already discussed" that I'm still convinced are plain wrong, and still haven't seen a good reason as to why they are right, which convinces me more each time that D will never hit mainstream.
Feb 18 2008
Well if Walter wants people to use his language, he needs to do some better convincing.I'm starting to suspect that in the effort to make the const system simple, it has become simplistic. -- Derek (skype: derek.j.parnell) Melbourne, Australia 19/02/2008 9:26:28 AM
Feb 18 2008
Derek Parnell wrote:I'm ok with simplistic as long as simple, common things remain simple. Don't know whether that's the case or not currently. --bbWell if Walter wants people to use his language, he needs to do some better convincing.I'm starting to suspect that in the effort to make the const system simple, it has become simplistic.
Feb 18 2008
Don't know whether that's the case or not currently.I've been using it for a while now, and on the whole I find it very simple, elegant, and obvious.
Feb 18 2008
On Tue, 19 Feb 2008 07:29:18 +0000, Janice Caron wrote:So long as one isn't trying to do things that Walter disagrees with. -- Derek Parnell Melbourne, Australia skype: derek.j.parnellDon't know whether that's the case or not currently.I've been using it for a while now, and on the whole I find it very simple, elegant, and obvious.
Feb 19 2008
Sergey Gromov wrote:I'm talking from the standpoint of generalization which you so much care about. When I generalize, I don't care how things are implemented. It's behaviour that matters. If I create an algorithm that uses references to invariant data, then it will work with anything that /behaves/ like such references. Even if they are actually ints passed by value.That's a good point, and a good reason why: invariant(C)[] c; invariant(int)[] i; should both have immutable array contents, i.e. if the contents of a reference is invariant then the reference itself should be invariant. The concept of having a mutable reference to immutable data is fundamentally flawed because it breaks the concept of what a reference is. A reference is not separable from what it refers to. If they were separable, they would be syntactically and semantically the same thing as pointers, and there would be no point whatsoever to even having a reference type.
Feb 19 2008
On Tue, 19 Feb 2008 12:49:09 -0800, Walter Bright wrote:invariant(C)[] c; invariant(int)[] i; should both have immutable array contents, i.e. if the contents of a reference is invariant then the reference itself should be invariant. The concept of having a mutable reference to immutable data is fundamentally flawed because it breaks the concept of what a reference is. A reference is not separable from what it refers to. If they were separable, they would be syntactically and semantically the same thing as pointers, and there would be no point whatsoever to even having a reference type.Ok given this position and that 'string' is 'invariant(char)[]' then string s; makes 's' a reference to an immutable array, and thus 's' should also be immutable, right? If so, does that mean that I cannot bind 's' to another literal - that is change the bits in 's' such that the .ptr and maybe .length properties have different values? string s = "abc'; // Initialized ok. s = "def"; // Should this fail because // I'm now changing an immutable reference? If your position re immutable references to hold, and if our codes needs mutable 'references' to immutable data, and thus we need to use pointers, what is the 'pointer' syntax for dynamic arrays that preserves array bounds checking? -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
Feb 19 2008
On 19/02/2008, Derek Parnell <derek psych.ward> wrote:Ok given this position and that 'string' is 'invariant(char)[]' then string s; makes 's' a reference to an immutable array,No, s is an array of immutable chars. Put another way, as I am sure you are well aware, s is a value type, whose layout is struct { invariant(char)* ptr; uint length; }If so, does that mean that I cannot bind 's' to another literals isn't a reference, and so the concept of "binding" doesn't make sense for it. What you can do is reassign it with another value. Basically, everything works, exactly as is it should.
Feb 19 2008
On Tue, 19 Feb 2008 22:18:29 +0000, Janice Caron wrote:On 19/02/2008, Derek Parnell <derek psych.ward> wrote:In that case, what did Walter really mean when he wrote:Ok given this position and that 'string' is 'invariant(char)[]' then string s; makes 's' a reference to an immutable array,No, s is an array of immutable chars. Put another way, as I am sure you are well aware, s is a value type, ...I took it that he was saying that 'c' and 'i' are references. -- Derek (skype: derek.j.parnell) Melbourne, Australia 20/02/2008 11:17:17 AMThat's a good point, and a good reason why: invariant(C)[] c; invariant(int)[] i; should both have immutable array contents, i.e. if the contents of a reference is invariant then the reference itself should be invariant.
Feb 19 2008
"Walter Bright" wroteSergey Gromov wrote:So please explain this: import std.stdio; class C { this(int n) {x = n;} int x; } void assignit(ref int src, ref int value) { src = value; } void assignit(C src, C value) { src = value; } void main() { int n = 1; int m = 2; C c = new C(1); C d = new C(2); assignit(n, m); assignit(c, d); writefln("%s %s %s %s", n, m, c.x, d.x); } // outputs 2 2 1 2 In both cases, the assignit function is taking reference types as arguments. C is a reference type because it is a class. ref int is a reference type because the compiler magically creates a reference. Both do the same thing, but yet the class version doesn't result in the value changing, because we are rebinding the reference, not copying the class itself. This is why your argument fails. There are some cases in D where references are treated as non-rebindable pointers to data, where acting on the reference is equivalent to acting on the pointed at data, and then there are classes, where you can rebind the reference in some cases, but in other cases you are acting on the data pointed to. I'm not saying that references should always be non-rebindable (I like the way classes work) or always be rebindable, I'm just saying that your argument against allowing references to be acted upon separate from the data is against the way the language/compiler currently is implemented. You can make the case that class references are not the same as non-rebindable references, and also that they are not like pointers. I would say that they are exactly like pointers except you cannot dereference them or perform general arithmetic on them. This puts them in a category on their own, which I think is fair game to say that it is reasonable that we can ask for that category to be modified without affecting the consistency of the other categories. The specific modification being that you can const-ify the data pointed to by a class reference without modifying the reference constness itself. -SteveI'm talking from the standpoint of generalization which you so much care about. When I generalize, I don't care how things are implemented. It's behaviour that matters. If I create an algorithm that uses references to invariant data, then it will work with anything that /behaves/ like such references. Even if they are actually ints passed by value.That's a good point, and a good reason why: invariant(C)[] c; invariant(int)[] i; should both have immutable array contents, i.e. if the contents of a reference is invariant then the reference itself should be invariant. The concept of having a mutable reference to immutable data is fundamentally flawed because it breaks the concept of what a reference is. A reference is not separable from what it refers to. If they were separable, they would be syntactically and semantically the same thing as pointers, and there would be no point whatsoever to even having a reference type.
Feb 19 2008
On 19/02/2008, Steven Schveighoffer <schveiguy yahoo.com> wrote:So please explain this: <snip> // outputs 2 2 1 2Simple. If you wanted the output to be 2 2 2 2 then the second function should have been declared void assignit(ref C src, ref C value) But you missed out the "ref"s, and so src was merely a local copy.In both cases, the assignit function is taking reference types as arguments.But in the second case, the reference is /local/. Function parameters declared without "ref" are just local variables. Assigning src will modify the local copy (of the reference), but you need the "ref" keyword if you want to modify the original (reference).Both do the same thing,No, they don't. Passing a value by reference is not the same thing as passing a reference by value.
Feb 19 2008
"Janice Caron" wroteOn 19/02/2008, Steven Schveighoffer wrote:You missed the point completely. I'm not asking to find bugs in my code, I'm rebutting Walter's argument that "a reference is not separable from what it refers to". If this was true in the current compiler, then I would expect the output to be 2 2 2 2, because assigning one reference to another should be like copying the value, right? Walter's argument is like saying "If the sky wasn't green, then dragons wouldn't exist". I'm not arguing his point about dragons, I'm saying, "wait a minute, the sky isn't green." -SteveSo please explain this: <snip> // outputs 2 2 1 2Simple. If you wanted the output to be 2 2 2 2 then the second function should have been declared void assignit(ref C src, ref C value) But you missed out the "ref"s, and so src was merely a local copy.In both cases, the assignit function is taking reference types as arguments.But in the second case, the reference is /local/. Function parameters declared without "ref" are just local variables. Assigning src will modify the local copy (of the reference), but you need the "ref" keyword if you want to modify the original (reference).Both do the same thing,No, they don't. Passing a value by reference is not the same thing as passing a reference by value.
Feb 19 2008
Walter Bright <newshound1 digitalmars.com> wrote:The concept of having a mutable reference to immutable data is fundamentally flawed because it breaks the concept of what a reference is. A reference is not separable from what it refers to. If they were separable, they would be syntactically and semantically the same thing as pointers, and there would be no point whatsoever to even having a reference type.A reference refers to data which is outside of the reference's body. This is the concept. A reference in a book, a C pointer, and a C++ reference are all realizations of this concept. The reason for C++ references to be immutable is obvious: the C++ designers wanted the C::operator=(C&) to work. D supports mutable references, so D references are not C++ references. D references are not the same as the data they refer to. They are much closer to pointers than in C++. The difference is in syntax. The point in having references in the language is the same as in C++: to use the same syntax for accessing objects, their members, and primitive types. This is required for proper generalization, and also simplifies program code. This is why references must support all possible type variants: they are instruments of generalization, so power of D templates depends directly on the power of references. -- SnakE
Feb 19 2008
Sergey Gromov wrote:Walter Bright <newshound1 digitalmars.com> wrote:That is only a small part of why D classes are reference types. The major reason is that polymorphism doesn't work for value types, it cries out for reference types. Value and reference types have different uses.The concept of having a mutable reference to immutable data is fundamentally flawed because it breaks the concept of what a reference is. A reference is not separable from what it refers to. If they were separable, they would be syntactically and semantically the same thing as pointers, and there would be no point whatsoever to even having a reference type.A reference refers to data which is outside of the reference's body. This is the concept. A reference in a book, a C pointer, and a C++ reference are all realizations of this concept. The reason for C++ references to be immutable is obvious: the C++ designers wanted the C::operator=(C&) to work. D supports mutable references, so D references are not C++ references. D references are not the same as the data they refer to. They are much closer to pointers than in C++. The difference is in syntax. The point in having references in the language is the same as in C++: to use the same syntax for accessing objects, their members, and primitive types.This is required for proper generalization, and also simplifies program code. This is why references must support all possible type variants: they are instruments of generalization, so power of D templates depends directly on the power of references.
Feb 19 2008
Walter Bright <newshound1 digitalmars.com> wrote:Sergey Gromov wrote:My argument was not about references vs values but about references vs pointers. I'm arguing about this statement:Walter Bright <newshound1 digitalmars.com> wrote:That is only a small part of why D classes are reference types. The major reason is that polymorphism doesn't work for value types, it cries out for reference types. Value and reference types have different uses.The concept of having a mutable reference to immutable data is fundamentally flawed because it breaks the concept of what a reference is. A reference is not separable from what it refers to. If they were separable, they would be syntactically and semantically the same thing as pointers, and there would be no point whatsoever to even having a reference type.A reference refers to data which is outside of the reference's body. This is the concept. A reference in a book, a C pointer, and a C++ reference are all realizations of this concept. The reason for C++ references to be immutable is obvious: the C++ designers wanted the C::operator=(C&) to work. D supports mutable references, so D references are not C++ references. D references are not the same as the data they refer to. They are much closer to pointers than in C++. The difference is in syntax. The point in having references in the language is the same as in C++: to use the same syntax for accessing objects, their members, and primitive types.Pointers, being a flavour of references, support polymorphism, too. The only difference from pointers is in syntax, and it is very important. The value types are different, or more precisely, as I've written earlier, any value type not containing references may be abstracted as a mutable reference to immutable data.If they (references---S.G.) were separable, they would be syntactically and semantically the same thing as pointers, and there would be no point whatsoever to even having a reference type.-- SnakEThis is required for proper generalization, and also simplifies program code. This is why references must support all possible type variants: they are instruments of generalization, so power of D templates depends directly on the power of references.
Feb 20 2008
On 16/02/2008, none <z gg.com> wrote:What I mean is in C++, you can define 2 different kinds of C++ pointers: Sorry in C++, it should be (1) C* const b; // b can be re-bind, but the object cannot be modified (2) const C* b and const C* const b; // both pointer, and data are const.I think you mistyped. (1) means "b is a const pointer to mutable data". In this case, therefore, b cannot be rebound. That would not be allowed in D because it breaks transitivity. On the other hand, the sentiment you expressed: "b can rebind, but the object cannot be modifed", can be expressed in both C++ and D as C const * b // C++ const C * b // C++, alternative syntax const(C)* b // D "Both pointer and data are const" can be written in both languages as C const * const b // C++ const C * const b // C++, alternative syntax const C* b; // D const(C*) b; // D, alternative syntax Both of my D examples assumed that the object C has been declared as a struct (in D), because otherwise you can't make an equivalence with C++. If C had been declared as a class in D, then things look a little different auto b = new C; // D There is no exact equivalent built into C++, although you can construct one artificially. C& b = *(new C()); // C++ This b will now behave just like a D reference. the C instance is on the heap, as required, and b is on the stack and four bytes big, as required. Now let's see what kind of constancy you can get: (1) C& b = ... (2) C& const b = ... (3) C const & b = ... (4) C const & const b = What may not be immediately obvious is that (1) and (2) are completely identical, because references in C++ are /always/ const. Likewise, (3) and (4) are completely identical, for the same reason. You absolutely /cannot/ do "mutable reference to const data" in C++. It's impossible. The best you can do is "mutable pointer to const data", and you /can/ do that in D. We're not missing out here!
Feb 16 2008
== Quote from Janice Caron (caron800 googlemail.com)'s articleI just want to make it clear again, nobody has what you called 'misconception'. By using my table, I'm saying '_reference_ in D is similar to _pointer_ in C++'! I think you have a 'misconception' that '_reference_ in D is similar to _reference_ in C++'! Just as you said: "References in C++ are /never/ rebindable"; but '(non-const) reference in D' is rebindable class C {} C c; c = c1; c = c2; // rebind! So '_reference_ in D is similar to _pointer_ in C++', not reference in C++! Since 'in C++, const C* p; // non-const pointer, const data' is allowed, why cannot we have 'non-const reference, const data' in D?But I just want to clear up one misconception. You /cannot/ do that in C++. References in C++ are /never/ rebindable.That's a terminology issue, to make it clear: class C {} D C++ ========================= =========================== reference: C c = new C(); pointer: C *c = new C(); pointer: C* cp = &c; ptr-to-ptr: C **cp = &c;
Feb 17 2008
On 17/02/2008, none <z gg.com> wrote:So '_reference_ in D is similar to _pointer_ in C++', not reference in C++!I disagree. I say a pointer is a pointer is a pointer, and that a pointer in C++ is similar (nay, identical) to a pointer in D.Since 'in C++, const C* p; // non-const pointer, const data' is allowed, why cannot we have 'non-const reference, const data' in D?Why not just substitute your C++ pointer with a D pointer? If it's acceptable to use a pointer in C++, then use the same pointer in D.
Feb 17 2008
Janice Caron wrote:On 17/02/2008, none <z gg.com> wrote:The difference is that in C++, 'new C' results in a C*, whereas in D it results in a C. Assuming C is a class, that is. So the C++ code "C* a = new C();" converts to the D code "C a = new C;". Now what he wants is to convert the C++ "const C* b = a;" to D "??? b = a;" with the semantics that b can be reassigned but the data behind it is unchangeable. I.e.: class Foo { public: int x; }; int main() { Foo* a = new Foo(); const Foo* b = a; /* here, G++ gives "error: assignment of data-member 'Foo::x' in read-only structure" */ b->x = 1; delete a; } Would become what, exactly, in D? (Disclaimer: I honestly don't know, but that's what I think he's asking for.) -- E-mail address: matti.niemenmaa+news, domain is iki (DOT) fiSince 'in C++, const C* p; // non-const pointer, const data' is allowed, why cannot we have 'non-const reference, const data' in D?Why not just substitute your C++ pointer with a D pointer? If it's acceptable to use a pointer in C++, then use the same pointer in D.
Feb 17 2008
On 17/02/2008, Matti Niemenmaa <see_signature for.real.address> wrote:Now what he wants is to convert the C++ "const C* b = a;" to D "??? b = a;" with the semantics that b can be reassigned but the data behind it is unchangeable.OK, I see that. But the thing is, it is never actually /necessary/ to do that. It is always possible to just write the code differently. There is really no pressing /need/ for "const class with mutable reference", since nobody has ever demonstrated a real-life use case that couldn't just be done differently. Certainly, no need pressing enough to demand a major change to generic programming and the type system. Also, remember that a C++ class is a D struct, and there's really no equivalent to a D class in C++.
Feb 17 2008
Janice Caron schrieb:On 17/02/2008, Matti Niemenmaa <see_signature for.real.address> wrote:Show me how I can maintain a simple map of class instances, which I get as const(C) from somewhere else, i.e. I have to accept the const here. example: const(C)[string] map; <- completely useless - you can do nothing with this construct The only possibility to solve this is to either use a cast or to use a struct S { const(C) obj } and modify the map to S*[string] (or something similar) - at least I don't see an alternative. This, of course, would also apply to some self-made map-like container.Now what he wants is to convert the C++ "const C* b = a;" to D "??? b = a;" with the semantics that b can be reassigned but the data behind it is unchangeable.OK, I see that. But the thing is, it is never actually /necessary/ to do that. It is always possible to just write the code differently. There is really no pressing /need/ for "const class with mutable reference", since nobody has ever demonstrated a real-life use case that couldn't just be done differently. Certainly, no need pressing enough to demand a major change to generic programming and the type system. Also, remember that a C++ class is a D struct, and there's really no equivalent to a D class in C++.
Feb 17 2008
On 17/02/2008, Sönke Ludwig <ludwig informatik_dot_uni-luebeck.de> wrote:Show me how I can maintain a simple map of class instances, which I get as const(C) from somewhere else, i.e. I have to accept the const here. example: const(C)[string] map; <- completely useless - you can do nothing with this constructSo change it to const(C)*[string] map; Now you've a map of mutable pointers, indexed by string. It's not hard.or to use a struct S { const(C) obj }That probably won't work in the future. You're basically exploiting a bug there, and I imagine that soon it will be fixed.
Feb 17 2008
Janice Caron schrieb:On 17/02/2008, Sönke Ludwig <ludwig informatik_dot_uni-luebeck.de> wrote:Since C is a class, const(C)* will mean a mutable pointer to a const class reference, which is not even allocatable with a simple syntax (was brought up here a while ago), also this would be an additional allocation, just like with the struct workaround (see below). Generally, I think that it is very desirable to be able to handle the reference/pointer part of a class C separate from the actual data in this respect. After all they are completely distinct in the underlying implementation.Show me how I can maintain a simple map of class instances, which I get as const(C) from somewhere else, i.e. I have to accept the const here. example: const(C)[string] map; <- completely useless - you can do nothing with this constructSo change it to const(C)*[string] map; Now you've a map of mutable pointers, indexed by string. It's not hard.No, was talking about creating a struct where the const reference stored on the heap - a mutable pointer to this struct is then stored in the map. If a new object is to replace an array entry, a new struct is allocated and a pointer to this new struct replaces the old one. Sorry, forgot an example - this is what I was thinking about: struct S { const(C) inst; } S*[string] map; map["hello"] = new S(someinst); All of this is and should always be possible, it does not break any const principle or anything. It's just that it requires an additional heap allocation and a lot of additional typing which should really not be necessary for such a basic thing.or to use a struct S { const(C) obj }That probably won't work in the future. You're basically exploiting a bug there, and I imagine that soon it will be fixed.
Feb 18 2008
Sorry, the "new S(someinst)" syntax will not work, of course. But you get the drift..
Feb 18 2008
Janice Caron Wrote:So change it to const(C)*[string] map; Now you've a map of mutable pointers, indexed by string. It's not hard.I don't feel good about sacrificing performance for something that I've lived without my whole programming career. The syntax is uglier, too. Your argument "we don't need it; there's always a workaround" is complete bollocks. We don't need high-level native-compiled languages at all, anything we can do in C or D we can in assembly language. We choose to use them because they encourage a more structured programming style with abstracted syntax. What you're basically encouraging is "workaround-oriented programming."
Feb 18 2008
On 17/02/2008, Matti Niemenmaa <see_signature for.real.address> wrote:Having a const class with mutable reference makes the language much much cleaner. The D docs themselves state that D is designed so that the programmer should rarely have to dip down to the level of pointers. Yet here we have a very important feature, const, that when used with an object reference cripples the reference so that it can no longer point to anything else, requiring us to use pointers when references should be able to suffice. D references are like Java references, and D const has similiarities with C++ const. I don't see why it should be so hard to mix Java-style references with C++ const, especially since Java style references are nothing more than syntactically pleasing pointers.Now what he wants is to convert the C++ "const C* b = a;" to D "??? b = a;" with the semantics that b can be reassigned but the data behind it is unchangeable.OK, I see that. But the thing is, it is never actually /necessary/ to do that. It is always possible to just write the code differently. There is really no pressing /need/ for "const class with mutable reference", since nobody has ever demonstrated a real-life use case that couldn't just be done differently. Certainly, no need pressing enough to demand a major change to generic programming and the type system.
Feb 17 2008
So why can't we have both (just as in C++): ======================== const B b; // b cannot be re-bind, and the object cannot be modified B const b; // b can be re-bind, but the object cannot be modified ========================The saddest part of this is it actually worked this way at least up through 2.007. I compiled the following code in a 2.007 compiler and when it worked, thought that everyone was crazy. Then I downloaded the 2.010 compiler and it wouldn't compile. So it's not even a matter of it being a lot of work to make it happen. I think everyone who is interested in having const work the older way should make keep making themselves heard! import std.stdio; class C { } int main() { C c1 = new C(); C c2 = new C(); const(C) cc = c1; cc = c2; // compiles with 2.007, but not 2.010 writeln("done!"); return 0; }
Feb 18 2008
"Sean Reque" <seanthenewt yahoo.com> wrote in message news:fpc5o0$2djh$1 digitalmars.com...When the latest const system became final, I was a little disappointed, but I was like "whatever". This stuff has been debated way too much and frankly I'm sick of hearing about it. Although I don't think it's going to change anything, I agree with you. Without this feature (whatever the syntax used to express it) the const system is simply incomplete. -CraigSo why can't we have both (just as in C++): ======================== const B b; // b cannot be re-bind, and the object cannot be modified B const b; // b can be re-bind, but the object cannot be modified ========================The saddest part of this is it actually worked this way at least up through 2.007. I compiled the following code in a 2.007 compiler and when it worked, thought that everyone was crazy. Then I downloaded the 2.010 compiler and it wouldn't compile. So it's not even a matter of it being a lot of work to make it happen. I think everyone who is interested in having const work the older way should make keep making themselves heard! import std.stdio; class C { } int main() { C c1 = new C(); C c2 = new C(); const(C) cc = c1; cc = c2; // compiles with 2.007, but not 2.010 writeln("done!"); return 0; }
Feb 18 2008
"none" wroteWhy can't we define re-assignable const reference variable? i.e. the variable can be re-bind, but it's allowed to change the object it points to:The problem here, none (is that your real name?), is that Walter has tried several times to achieve exactly that, and each time the syntax that he has created is either confusing or breaks something else. I think he has given up, claiming that there is no way to do it, but I think he is wrong in that respect. The problem stems from the fact that classes are inherently references and everything else is not. This in itself is not a problem, and is a distinction I happen to agree with, but the issue is that there is no easy way to const-modify the data of a class without also modifying the reference to the data. In order for this to work, there needs to be a syntax change. In all the responses to this thread, there is one point of view that I wish to rebut: "You can't have mutable references to const classes because any syntax change you have to make would break generic programming" Generic programming is already broken. That is, because classes *are* references and must be created from the heap using the new operator, you must treat them differently today than other types. For example, if I want to create a generic type that creates a new version of a type, or uses an array of the type, depending on whether the type is a class or a struct or something else, I need to use static if to determine this before creating the new type. I believe others have pointed out other examples, but it all comes down to the fact that yes, classes are inherently different than structs or other data types, and you have to treat them differently, so saying you cannot change the language because then you'd have to treat classes differently than other types is asinine. I have proposed two syntax changes that I believe would resolve the problem. One is to allow dereferencing a class type, such as: const(*C)* c; Which would translate to *C being the value of type C, and therefore const(*C)* being exactly what we want. This does not add any keywords, and also utilizes the * operator in familiar ways, and so it would be in my mind trivial to introduce and implement in the compiler. The only issue is that you must restrict the user from declaring a variable or return type of the dereferenced class type. i.e.: *C cvalue; would be illegal. The only drawback here is that code is going to get really ugly, but I can live with this because we can make templates that make the code look better. And in fact, this *fixes* to some degree the difference between classes and structs for generic programming, because if you want a reference type, you can do: valuetype(T) { static if(is(T == class)) alias *T valuetype; else alias T valuetype; } struct hasTailconstRef(T) { const(valuetype!(T)) * myref; } now, hasTailconstRef.myref is a tailconst reference to a type no matter if the type is a class, struct, int, or whatever. The other proposal I have made, which I like better but would be a more drastic syntax change, is to have a reference operator that "pulls out" the reference on a class. Other types would be treated like references to the type: struct S {} class C {} S & s; // equivalent to S * s C & c; // equivalent to C c int & i; // equivalent to int * i With this, you can then use the & operator to declare a tailconst reference to a class or struct equivalently: const(C) & c; const(S) & s; I have never read any arguments that correctly refute that these options would work. All I have ever heard is the generic programming argument, which is totally bogus, and "we've already tried tail-const, it doesn't work", which isn't an argument at all. I challenge anyone to tell me why either of these schemes would not work. -Steve
Feb 19 2008
here's my random thought on the subject (just wanted to throw those in the mix...): [warning: long post ahead] the current (and all previous) const designs fail due to too narrow a view on the issue. when introducing a const system to a language than the language as a whole should be examined and related concepts should be tweaked accordingly. So here's my list of those related issues: references - in a high level language like D you should be able to just use refs everywhere and pointer usage should be discouraged. D as a systems programming language, should however provide pointers for those /advanced/low-level/potentially unsafe uses when you do systems programming. that means that refs should be enhanced in D and pointers should be used _only_ when truly you need them (for example for pointer arithmetic). for example: you should be able to use (and it should be the preferred way!): ref S s1 = new S(); // S is a struct instead of the equivalent: S* s2 = new S(); so you can eliminate pointers from almost all user code. how does this affect const? i suggest the following: const(T) t = new T(); // this would be a mutable ref to const T const(ref T) t = new T(); // this would be a const ref to const T and you can also define "const T" as a shortcut for "const(ref T)" i know that this means const(T) isn't the same as "const T" but I think that this is a reasonable compromise (if it's consistent for all types) another issue with refs is that i want to be able to return the lvalue by specifying the return type to be ([const] ref T). another issue is a function call - there are really only two modes for passing a parameter to a function: 1. you allow the function to change the outside(actual) parameter 2. you do not allow the function to do that. value vs. ref semantics is an implementation detail that user level code shouldn't care about at all, and a special syntax should be provided and used to distinguish the two only for advanced use cases. so for example you could define: void func_name(in T t); in the above example the in keyword would represent the fact that you cannot change the outside parameter. how do you implement it? the compiler should have a very simple heuristic that says that if T is a primitive value or a small struct than just pass it by value and if it's a class instance than pass it as a const ref. that is an optimization the compiler should provide. now, what if i want to explicitly choose the parameter passing semantics? that is also possible (but discouraged for user level code) with a bit more verbose code and language rules. for example primitives should be passed by value be default and you can change that with a ref keyword. class instances are passed by ref so you can pass them by value if they implement a dup method, and the user must call that explicitly. so, other_func(someClassInstance.dup()); passes someClassInstance by value. the second mode above is simply pass T by ref. also a bigger change could be done so that the default mode when passing parameters is 1. so you won't need to specify in and it would be implied. for generic programming to work it needs to use the above "in" and "ref" (i.e. modes 1 and 2) and not rely on a specific parameter passing semantics unless this is what needed. one last thing: i really liked oskar's orthogonal const proposal and wish for it to be further explored. anyway, that is just my shnekel (2 NIS) that i wanted to add to the discussion. --Yigal
Feb 19 2008
Yigal Chripun <yigal100 gmail.com> wrote:i suggest the following: const(T) t = new T(); // this would be a mutable ref to const T const(ref T) t = new T(); // this would be a const ref to const T and you can also define "const T" as a shortcut for "const(ref T)" i know that this means const(T) isn't the same as "const T" but I think that this is a reasonable compromise (if it's consistent for all types) another issue with refs is that i want to be able to return the lvalue by specifying the return type to be ([const] ref T).Please, why invent new syntax ? const(T) t; // mutable ref to const T const{T t;} // const ref to const T, because of transitiviness This syntax even worked in one of the previous compiler versions! -- SnakE
Feb 19 2008
"Sergey Gromov" wrotePlease, why invent new syntax ? const(T) t; // mutable ref to const T const{T t;} // const ref to const T, because of transitiviness This syntax even worked in one of the previous compiler versions!Yes, this is one of the trials of Walter to see if he could get tail-const to work. The problem is if T is not a reference/pointer (such as int). Now: const(T) t; T t; are equivalent, which is necessary to make that const system work. To have some variable declared as const(T), and then allow assignment to that variable is completely inconsistent with the fundamental usage of parentheses. If you have something defined as f(x), the entirety of x should be affected by f. This is why that system was dropped, as it should have been. -Steve
Feb 19 2008
Steven Schveighoffer <schveiguy yahoo.com> wrote:"Sergey Gromov" wroteIf you create a generic algorithm which works with T, and declare something as const(T) t; then you effectively assert that you're going to replace t with different other Ts, but promise to keep integrity of a referenced T intact, if anything is referenced at all. This means that for int, which is not referencing anything, const(int) t; is completely and safely equivalent to int t; without breaking any contracts of your algorithm. Please provide an example where "const(int) x;" absolutely must mean "const int x;" for a generic algorithm to work properly. -- SnakEPlease, why invent new syntax ? const(T) t; // mutable ref to const T const{T t;} // const ref to const T, because of transitiviness This syntax even worked in one of the previous compiler versions!Yes, this is one of the trials of Walter to see if he could get tail-const to work. The problem is if T is not a reference/pointer (such as int). Now: const(T) t; T t; are equivalent, which is necessary to make that const system work. To have some variable declared as const(T), and then allow assignment to that variable is completely inconsistent with the fundamental usage of parentheses. If you have something defined as f(x), the entirety of x should be affected by f. This is why that system was dropped, as it should have been.
Feb 20 2008
On 20/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:This means that for int, which is not referencing anything, const(int) t; is completely and safely equivalent to int t;Sergey, there may well be merit in the idea of having some form of syntax which implies rebindable const classes. I'm not necessarily against the idea. However, I most wholeheartedly /am/ against allowing any kind of move which suggests that const(int) shall mean mutable int! One of the reasons that that syntax was ditched was because it was damnably confusing, and got many, many complaints from people who were using it. Not only did const(int) mean "mutable int", but even if you could get your head round that one, it turned out that const (int *)* p; and const (int **) p; were completely equivalent. And I have absolutely no idea what the syntax for array of const ints was. Was it "const(int)[]"? Was it something else? I mean, it was just too confusing for words. No way can we /ever/ go back to that. For any type, T, const(T) absolutely /must/ mean that T is const. So ... if you want widespread, across-the-board support for rebindable class references, please, please, please choose a different syntax to campaign for. Several syntaxes have been suggested in the past, including const(T)& /* by me */ ref const(T) const(*T)* tailconst(T) TailConst!(T) and so on, any or all of which could work, if Walter finds a way to make it possible. But not const(T). Anything else, just not const(T).
Feb 20 2008
Janice Caron <caron800 googlemail.com> wrote:On 20/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:Pointers ruin my beautiful theory. :-) They are different. They do not generalize with references. So I propose to outlaw them completely: let them be an advanced, unsafe, low- level feature. So that pointers can never be const, and an explicit cast is /always/ required to convert from reference to pointer and back. To do this, references must be powerful enough to replace pointers for any high-level tasks. For instance, structs should always be passed by reference unless they are invariant and small.This means that for int, which is not referencing anything, const(int) t; is completely and safely equivalent to int t;[...] One of the reasons that that syntax was ditched was because it was damnably confusing, and got many, many complaints from people who were using it. Not only did const(int) mean "mutable int", but even if you could get your head round that one, it turned out that const (int *)* p; and const (int **) p; were completely equivalent.And I have absolutely no idea what the syntax for array of const ints was. Was it "const(int)[]"? Was it something else?Easy. An array of const ints is "const(int[]) x;" You can't change ints, you can't change length nor ptr either. You can replace the whole thing though because x is not const (is outside the parentheses).I mean, it was just too confusing for words. No way can we /ever/ go back to that. For any type, T, const(T) absolutely /must/ mean that T is const.My concept is very simple. Everything within the scope of const is const, everything outside is not. The confusion arises in two cases: a) trying to apply constness to primitive types. It really may be hard to understand why const(int) does nothing. But you don't need to use this syntax in everyday programming. What you really need is const(T) to behave consistently for different T. C++ allows to call a destructor for int for exactly the same reason, and b) when you use const for pointers and experience completely different behaviour from references. This is because pointers are too different, and you can't do without pointers in D at the moment. This should be fixed. -- SnakE
Feb 20 2008
On 20/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:> I mean, it was just too confusing for words. No way > can we /ever/ go back to that. For any type, T, const(T) absolutely > /must/ mean that T is const. My concept is very simple. Everything within the scope of const is const, everything outside is not.Not good enough. Everything inside the /brackets/ must be const. Otherwise, don't call it const, call it something else. Call it "tailconst" or "rebindable" or whatever, but don't call it const, because it isn't. I want to be able to introduce newbies to D and tell them how wonderful it is. I can't do that if const(T) doesn't mean const T. Really. Back it D2.007 - the version of const that you like, but most people didn't, we had five different kinds of const. Count them. Five. They were: final T // head const const(T) // tail const const T // fully const invariant(T) // tail invariant invariant T // fully invariant ...and that's not counting the use of "in" in function declarations. It was just too silly for words. Right now, in D2.011, "invariant(char)[]" is a string. That makes absolutely perfect sense. Long may that remain. What is your problem with just choosing a different word, or a different syntax? You'd get a lot more support for the idea that way. I certainly wouldn't be arguing with you in that case.
Feb 20 2008
Janice Caron <caron800 googlemail.com> wrote:On 20/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:I am a newbie. I want consistency in the language. This is what attracts me.> I mean, it was just too confusing for words. No way > can we /ever/ go back to that. For any type, T, const(T) absolutely > /must/ mean that T is const. My concept is very simple. Everything within the scope of const is const, everything outside is not.Not good enough. Everything inside the /brackets/ must be const. Otherwise, don't call it const, call it something else. Call it "tailconst" or "rebindable" or whatever, but don't call it const, because it isn't. I want to be able to introduce newbies to D and tell them how wonderful it is. I can't do that if const(T) doesn't mean const T. Really.Back it D2.007 - the version of const that you like, but most people didn't, we had five different kinds of const. Count them. Five. They were: final T // head const const(T) // tail const const T // fully const invariant(T) // tail invariant invariant T // fully invariantCan't see anything wrong here. Except that you omit the variable for some reason. Const only has meaning when applied to a reference. So: const(T) x; // tail const const{T x;} // full const Simple. Clean....and that's not counting the use of "in" in function declarations. It was just too silly for words.As a newbie, I was really confused by a number of ways one can specify constness of an argument. This deserves a separate post. What I'm sure of, no "const," "const{}" or "const:" should be allowed there which all are different forms of a const attribute. Note that my confusion was about 2.010 which you probably consider 'fixed.'Right now, in D2.011, "invariant(char)[]" is a string. That makes absolutely perfect sense. Long may that remain.Can't see any sense in making ptr and length variable. This makes strings 'somewhat const' to me. Not really const.What is your problem with just choosing a different word, or a different syntax? You'd get a lot more support for the idea that way. I certainly wouldn't be arguing with you in that case.Actually, const() syntax is already different from const attribute. Probably if we had a tailconst attribute instead, so that it was possible to write tailconst { C c; int x; // either illegal, or not affected } this would be quite enough, and pretty consistent. This should of course deprecate the use of non-attribute const() form. But it would have a strange effect for structs anyway: with "tailconst S s;", which in my syntax is "const(S) s;", you won't be able to "s.whatever = newValue", but it would be legal to tailconst S s = initializer; S var = s; // contents copied var.whatever = newValue; s = var; // legal for tailconst otherwise generic algorithms won't work. I see your main concern is educational. This is resolved very simple, too: teach that /everything/ in D are objects, and everything is by reference. But compiler resolves many of the references at compile time. This is not strictly true because most references are resolved at language design time, but it doesn't invalidate the thesis itself. -- SnakE
Feb 20 2008
On 20/02/2008, Janice Caron <caron800 googlemail.com> wrote:If you want the array also to be invariant - no problemo! Just put the array inside the brackets too - "invariant(char)[]".That was a typo. Allow me to correct myself. If you want the array also to be invariant - no problemo! Just put the array inside the brackets too - "invariant(char[])".
Feb 20 2008
On 20/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:Const only has meaning when applied to a reference.Hardly. Const is perfectly meaningful when applied to a value!So: const(T) x; // tail const const{T x;} // full const Simple. Clean.Yuk! Fortunately, I just don't believe Walter will go for that.> Right now, in D2.011, "invariant(char)[]" is a string. That makes > absolutely perfect sense. Long may that remain. Can't see any sense in making ptr and length variable. This makes strings 'somewhat const' to me. Not really const.Well then you really haven't understood it all. The characters of a string may be stored in a ROM segment, and for that reason, the characters of a string may not be modified. But there is no reason why you can't modify slices which merely point into that ROM data. Don't you see that "invariant(char)" means exactly that!? Chars that are invariant - it doesn't get much simpler. And "[]" means "array of". Hence, "invariant(char)[]" = "array of invariant chars". If you want the array also to be invariant - no problemo! Just put the array inside the brackets too - "invariant(char)[]". I'm not describing anything exotic here - I'm describing the system as it is now - simple, elegant, and obvious.Actually, const() syntax is already different from const attribute.Again, you're wrong. The following two lines const int x; const(int)x; are identical in meaning. And that remains true for any type, no matter how complicated, e.g. const int[]* p; const(int[]*)p; Again, completely identical. You are partly correct in that "const" /when applied to member functions/ means something different, and that is something which bugs me a little. But member functions aside, the const attribute just makes things const, which is exactly what you'd expect.Probably if we had a tailconst attribute instead, so that it was possible to write tailconst { C c; int x; // either illegal, or not affected }That is something which no one has ever suggested before! Oh, plenty of people have suggested tailconst, but it's generally expected to be more along the lines of tailconst(C) c;This should of course deprecate the use of non-attribute const() form.You can't! How could you declare const(int[][][])[][][] x; without the brackets? (Not that I have a use for that particular type, but hopefully you see the point)."tailconst S s;", which in my syntax is "const(S) s;"If you stop calling it const(S), I'll stop arguing with you. :-). I'm still on the fence as to its utility, and Walter still says he can't implement it, but if people want it, and Walter turns out to be wrong, I certainly won't complain.I see your main concern is educational. This is resolved very simple, too: teach that /everything/ in D are objects, and everything is by reference.Teaching lies is just plain wrong. D has both value type and reference types.
Feb 20 2008
Janice Caron <caron800 googlemail.com> wrote:Well then you really haven't understood it all. The characters of a string may be stored in a ROM segment, and for that reason, the characters of a string may not be modified.Of course I understand that.But there is no reason why you can't modify slices which merely point into that ROM data.Modifying a slice which points i-dont-know-where feels unsafe to me. I won't use this feature as long as I can.I'm talking about syntax, not semantics. const is an attribute, const() is a function. I believe that the language lexer was specifically modified to allow for this functional const notation.Actually, const() syntax is already different from const attribute.Again, you're wrong. The following two lines const int x; const(int)x; are identical in meaning. And that remains true for any type, no matter how complicated, e.g.This is strange. tailconst attribute merges smoothly with the language design. On the contrary, the functional attributes, const included, look strange.Probably if we had a tailconst attribute instead, so that it was possible to write tailconst { C c; int x; // either illegal, or not affected }That is something which no one has ever suggested before! Oh, plenty of people have suggested tailconst, but it's generally expected to be more along the lines of tailconst(C) c;This use of "partial const", in addition to "full const" and "tail const", is specific to multi-dimentional arrays. No other types can make use of it. With arrays, you probably can do with aliasing: alias const int[][][] constArr; constArr[][][] x; -- SnakEThis should of course deprecate the use of non-attribute const() form.You can't! How could you declare const(int[][][])[][][] x; without the brackets? (Not that I have a use for that particular type, but hopefully you see the point).
Feb 20 2008
On 20/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:Modifying a slice which points i-dont-know-where feels unsafe to me. I won't use this feature as long as I can.string s = "hello world"; s = s[6..$]; In what way is this unsafe?> How could you declare > > const(int[][][])[][][] x; > > without the brackets? This use of "partial const", in addition to "full const" and "tail const", is specific to multi-dimentional arrays. No other types can make use of it.Sure they can const(int***)*** x; or, perhaps more usefully int[const(int)[]] map; There are an infinity of possible examples.With arrays, you probably can do with aliasing: alias const int[][][] constArr; constArr[][][] x;And this to you would be a good thing?
Feb 20 2008
Janice Caron <caron800 googlemail.com> wrote:On 20/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:This is Ok. It's changing the .length directly which I don't like, and which is actually unpredictable.Modifying a slice which points i-dont-know-where feels unsafe to me. I won't use this feature as long as I can.string s = "hello world"; s = s[6..$]; In what way is this unsafe?Ok I see. Rounding up our discussion, all the argument was because I misunderstood the type system. And, judging from this syntax is discussed often and even was supported in the compiler for some time, I'm not alone in my misunderstanding. Seems like an educational problem. -- SnakE> How could you declare > > const(int[][][])[][][] x; > > without the brackets? This use of "partial const", in addition to "full const" and "tail const", is specific to multi-dimentional arrays. No other types can make use of it.Sure they can const(int***)*** x; or, perhaps more usefully int[const(int)[]] map; There are an infinity of possible examples.
Feb 21 2008
On 21/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:Janice Caron <caron800 googlemail.com> wrote: This is Ok. It's changing the .length directly which I don't like, and which is actually unpredictable.It's always safe, and it's always predictable. It's just not very useful. string s = "hello"; s.length = 10; s will now contain "hello" followed by five default-value chars. Given that string contents are immutable, that's completely pointless. But it makes a lot more sense with non-constant arrays. For example: char[] s; s.length = 5; /* blah */ s.length = 25; /* blah */ s.length = 10; etc. In this case, the buffer will be reallocated somewhere else, and the original contents copied so you don't lose anything. It's exactly like calling realloc() in C or C++.
Feb 21 2008
Janice Caron wrote:char[] s; s.length = 5; /* blah */ s.length = 25; /* blah */ s.length = 10; etc. In this case, the buffer will be reallocated somewhere else, and the original contents copied so you don't lose anything. It's exactly like calling realloc() in C or C++.Well, there's one difference between what happens there and realloc(); the latter deallocates the original while D leaves the original in place in case there are other references to it. (This is more workable in D than C/C++ though, since if there aren't the GC will clean it up)
Feb 21 2008
Sergey Gromov wrote:Steven Schveighoffer <schveiguy yahoo.com> wrote:I wasn't aware of tat syntax. Please retract all comments I made in this thread, this is exactly what I was looking for."Sergey Gromov" wroteIf you create a generic algorithm which works with T, and declare something as const(T) t; then you effectively assert that you're going to replace t with different other Ts, but promise to keep integrity of a referenced T intact, if anything is referenced at all. This means that for int, which is not referencing anything, const(int) t; is completely and safely equivalent to int t; without breaking any contracts of your algorithm. Please provide an example where "const(int) x;" absolutely must mean "const int x;" for a generic algorithm to work properly.Please, why invent new syntax ? const(T) t; // mutable ref to const T const{T t;} // const ref to const T, because of transitiviness This syntax even worked in one of the previous compiler versions!Yes, this is one of the trials of Walter to see if he could get tail-const to work. The problem is if T is not a reference/pointer (such as int). Now: const(T) t; T t; are equivalent, which is necessary to make that const system work. To have some variable declared as const(T), and then allow assignment to that variable is completely inconsistent with the fundamental usage of parentheses. If you have something defined as f(x), the entirety of x should be affected by f. This is why that system was dropped, as it should have been.
Feb 20 2008
"Robert Fraser" wroteSergey Gromov wrote:Hm... maybe true, but this is not the supported syntax for the current or future compilers, so you will be stuck at D 2.004 or something (can't remember which one). Don't retract those comments just yet ;) -SteveSteven Schveighoffer wrote:I wasn't aware of tat syntax. Please retract all comments I made in this thread, this is exactly what I was looking for."Sergey Gromov" wroteIf you create a generic algorithm which works with T, and declare something as const(T) t; then you effectively assert that you're going to replace t with different other Ts, but promise to keep integrity of a referenced T intact, if anything is referenced at all. This means that for int, which is not referencing anything, const(int) t; is completely and safely equivalent to int t; without breaking any contracts of your algorithm. Please provide an example where "const(int) x;" absolutely must mean "const int x;" for a generic algorithm to work properly.Please, why invent new syntax ? const(T) t; // mutable ref to const T const{T t;} // const ref to const T, because of transitiviness This syntax even worked in one of the previous compiler versions!Yes, this is one of the trials of Walter to see if he could get tail-const to work. The problem is if T is not a reference/pointer (such as int). Now: const(T) t; T t; are equivalent, which is necessary to make that const system work. To have some variable declared as const(T), and then allow assignment to that variable is completely inconsistent with the fundamental usage of parentheses. If you have something defined as f(x), the entirety of x should be affected by f. This is why that system was dropped, as it should have been.
Feb 20 2008
"Sergey Gromov" wroteSteven Schveighoffer wrote:Sergey, I am not arguing that the functionality that you wish to have is invalid. In fact, I would have been ok with that syntax, and understood it once it was explained thoroughly. But I have to say that I agree with Janice and Walter on this one, it was very confusing. It just goes against the traditional usage of parentheses. The idea is correct, the syntax is confusing. Find another syntax. -Steve"Sergey Gromov" wroteIf you create a generic algorithm which works with T, and declare something as const(T) t; then you effectively assert that you're going to replace t with different other Ts, but promise to keep integrity of a referenced T intact, if anything is referenced at all. This means that for int, which is not referencing anything, const(int) t; is completely and safely equivalent to int t; without breaking any contracts of your algorithm. Please provide an example where "const(int) x;" absolutely must mean "const int x;" for a generic algorithm to work properly.Please, why invent new syntax ? const(T) t; // mutable ref to const T const{T t;} // const ref to const T, because of transitiviness This syntax even worked in one of the previous compiler versions!Yes, this is one of the trials of Walter to see if he could get tail-const to work. The problem is if T is not a reference/pointer (such as int). Now: const(T) t; T t; are equivalent, which is necessary to make that const system work. To have some variable declared as const(T), and then allow assignment to that variable is completely inconsistent with the fundamental usage of parentheses. If you have something defined as f(x), the entirety of x should be affected by f. This is why that system was dropped, as it should have been.
Feb 20 2008
Steven Schveighoffer <schveiguy yahoo.com> wrote:"Sergey Gromov" wroteThe traditional usage of parentheses is this: foo(x). This means that a function foo is applied to its argument x, and not applied to everything else. You are probably talking about some different tradition. Please clarify. -- SnakEIf you create a generic algorithm which works with T, and declare something as const(T) t; then you effectively assert that you're going to replace t with different other Ts, but promise to keep integrity of a referenced T intact, if anything is referenced at all. This means that for int, which is not referencing anything, const(int) t; is completely and safely equivalent to int t; without breaking any contracts of your algorithm. Please provide an example where "const(int) x;" absolutely must mean "const int x;" for a generic algorithm to work properly.Sergey, I am not arguing that the functionality that you wish to have is invalid. In fact, I would have been ok with that syntax, and understood it once it was explained thoroughly. But I have to say that I agree with Janice and Walter on this one, it was very confusing. It just goes against the traditional usage of parentheses. The idea is correct, the syntax is confusing. Find another syntax.
Feb 20 2008
On 20/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:The traditional usage of parentheses is this: foo(x). This means that a function foo is applied to its argument x, and not applied to everything else. You are probably talking about some different tradition. Please clarify.Happy to. It's the exact same tradition, except that the function in question is called "const", not "foo". It takes a type as it's input (e.g int), and yeilds a type as its output (in this case const int).
Feb 20 2008
Janice Caron <caron800 googlemail.com> wrote:On 20/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:I see, thank you. It's really natural to think of const() as of a type- yielding function, sort of typeof(), which never came to my mind for some reason. But here is the caveat. As I understand from your posts, you state that "const(C) x;", as well as "const C x;", declares a variable of type (const C). But this is not true. It actually declares a variable of type "const ref to const C". Since declaration "C x;" declares x of type "ref to C", I seem to automatically assume that a declaration is actually C ref x; and therefore "const(C) x;" is actually "const(C) ref x;" which gives a variable x of type "ref to const C". A C++ habit, I presume. But it doesn't mean it's a bad approach. -- SnakEThe traditional usage of parentheses is this: foo(x). This means that a function foo is applied to its argument x, and not applied to everything else. You are probably talking about some different tradition. Please clarify.Happy to. It's the exact same tradition, except that the function in question is called "const", not "foo". It takes a type as it's input (e.g int), and yeilds a type as its output (in this case const int).
Feb 20 2008
On 20/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:As I understand from your posts, you state that "const(C) x;", as well as "const C x;", declares a variable of type (const C). But this is not true. It actually declares a variable of type "const ref to const C".No. Consider const(int) x; This does not declare a variable of type "const ref to const int", it declares a const int. I understand that you're thinking of classes, but even with classes, you're not quite getting what a class is. A class is /not/ the data on the heap. (If that were so, it would be possible to create an array of dereferenced class instances, and it isn't). No, a class /is the reference/ - and indirectly, what that reference points to. Thus, a const class /is/ a const reference. A "tailconst" class, on the other hand, would be a class (by which I mean, a reference) whose tail (the data on the heap) was const.
Feb 20 2008
what if we separate const into two keywords? a) const would apply to data only. (transitively) b) "bound" ( a new keyword ) would apply to references only (transitively) the idea is as follows: Class c1 = new Class(); //all mutable const Class c2 = new Class(); // mutable ref to const data same as: const(Class) c3 = new Class(); bound const Class c4 = new Class(); // bound (ie const) ref to const data const int a; // a is const bound int a; // illegal bound Class c5 = new Class(); // const ref... etc... that's just a start of a start of an idea. it could be developed much further... like where the "invariant" concept would fit in with such a scheme. -- Yigal Janice Caron wrote:On 20/02/2008, Sergey Gromov <snake.scaly gmail.com> wrote:As I understand from your posts, you state that "const(C) x;", as well as "const C x;", declares a variable of type (const C). But this is not true. It actually declares a variable of type "const ref to const C".No. Consider const(int) x; This does not declare a variable of type "const ref to const int", it declares a const int. I understand that you're thinking of classes, but even with classes, you're not quite getting what a class is. A class is /not/ the data on the heap. (If that were so, it would be possible to create an array of dereferenced class instances, and it isn't). No, a class /is the reference/ - and indirectly, what that reference points to. Thus, a const class /is/ a const reference. A "tailconst" class, on the other hand, would be a class (by which I mean, a reference) whose tail (the data on the heap) was const.
Feb 20 2008
On 20/02/2008, Yigal Chripun <yigal100 gmail.com> wrote:bound const Class c4 = new Class(); // bound (ie const) ref to const dataWouldn't the word "const" be superfluous in that example, since constancy is transitive? (If the reference is constant, the data /must/ be). It's an interesting idea, but I think, in general, if the compiler sees an array like const(T)[] x; then it has to mean that the array's contents are not modifiable. That rule shouldn't depend on T, it should simply be true always. Ditto all other collections.
Feb 20 2008
Janice Caron wrote:On 20/02/2008, Yigal Chripun <yigal100 gmail.com> wrote:As I've already said: it's only a start of an idea and should be further refined. that said, you are right that it's superfluous in the example above. I've mainly suggested a new keyword and the idea to seperate the two use cases of const. I'm not sure if the "bound" property should be transitive or not ( i suggested that it is but all options should be explored..) and it all depends on what semantics you want to achieve. maybe (probably) bound should also imply const on the referred data and const would imply all refs inside the data object to be bound. another tweak that can be done: intead of an error, if you apply bound to a value type (like a primitive) the compiler implicitly "casts" that to a const, that way you example above of an array would work for any type T. it could be used the same way in generic programming. --Yigalbound const Class c4 = new Class(); // bound (ie const) ref to const dataWouldn't the word "const" be superfluous in that example, since constancy is transitive? (If the reference is constant, the data /must/ be). It's an interesting idea, but I think, in general, if the compiler sees an array like const(T)[] x; then it has to mean that the array's contents are not modifiable. That rule shouldn't depend on T, it should simply be true always. Ditto all other collections.
Feb 20 2008
Yigal Chripun wrote:Janice Caron wrote:after thinking about the above here are my thoughts: the problem is trying to apply a single rule to two very different concepts, so either way you get some type of a compromise. so why not just realize we have a duality in D and plan accordingly. thus instead of the current rule which states: for every type T, const(T) means that all of T is const and from it derived the rule that const T = const(T) and replace it with: if T has value semantics (primitive, union, struct, enum, ..) than the above rule applies. else, T is a reference type (a class) and const(T) means _only_ that the instance data is const, and its reference is _not_. what we get is that const(T)=const T only for value types. now, instead of my proposed "bound" keyword, let's just use final which is already a reserved keyword. final will always imply const too because of const transitivity (it'll be a superset of const). that way for value types the following are identical: const(S) s; final S s; final const S s; // could be reported by the compiler as redundant const S s; and for reference types (classes) we get the following behavior: const(C) c = new C(); // mutable ref to const data const C c = new C(); // same as above (compiler could issue a warning for lack of parens) final const(C) c = new C(); // const ref to const data final const C c = new C(); //same as above final C c = new C(); //same as above no issues with const(int) being mutable and other unintuitive syntaxes. generic programming - you can choose to use const(T)/const T for a weaker input condition or a final T for a stronger input condition that will enforce full constancy of T for all types. for function definitions: 'in' should be mapped to const as defined above, and as I suggested before the compiler should choose if he passes the parameter by value or by reference with optional control of that by the user (for system programming..) also it could be worthwhile to make in the default. D community - what do you think? am I totally wrong or is it a sane and more powerful solution to const? -- YigalOn 20/02/2008, Yigal Chripun <yigal100 gmail.com> wrote:As I've already said: it's only a start of an idea and should be further refined. that said, you are right that it's superfluous in the example above. I've mainly suggested a new keyword and the idea to seperate the two use cases of const. I'm not sure if the "bound" property should be transitive or not ( i suggested that it is but all options should be explored..) and it all depends on what semantics you want to achieve. maybe (probably) bound should also imply const on the referred data and const would imply all refs inside the data object to be bound. another tweak that can be done: intead of an error, if you apply bound to a value type (like a primitive) the compiler implicitly "casts" that to a const, that way you example above of an array would work for any type T. it could be used the same way in generic programming. --Yigalbound const Class c4 = new Class(); // bound (ie const) ref to const dataWouldn't the word "const" be superfluous in that example, since constancy is transitive? (If the reference is constant, the data /must/ be). It's an interesting idea, but I think, in general, if the compiler sees an array like const(T)[] x; then it has to mean that the array's contents are not modifiable. That rule shouldn't depend on T, it should simply be true always. Ditto all other collections.
Mar 06 2008
On Thu, 06 Mar 2008 20:21:32 +0100, Yigal Chripun <yigal100 gmail.com> = wrote:Yigal Chripun wrote:onst =Janice Caron wrote:On 20/02/2008, Yigal Chripun <yigal100 gmail.com> wrote:bound const Class c4 =3D new Class(); // bound (ie const) ref to c=atdataWouldn't the word "const" be superfluous in that example, since constancy is transitive? (If the reference is constant, the data /must/ be). It's an interesting idea, but I think, in general, if the compiler sees an array like const(T)[] x; then it has to mean that the array's contents are not modifiable. Th=llrule shouldn't depend on T, it should simply be true always. Ditto a=herother collections.As I've already said: it's only a start of an idea and should be furt=userefined. that said, you are right that it's superfluous in the example above. I've mainly suggested a new keyword and the idea to seperate the two =cases of const. I'm not sure if the "bound" property should be transitive or not ( i suggested that it is but all options should be explored..) and it all=depends on what semantics you want to achieve. maybe (probably) bound=lshould also imply const on the referred data and const would imply al=drefs inside the data object to be bound. another tweak that can be done: intead of an error, if you apply boun=atto a value type (like a primitive) the compiler implicitly "casts" th=to a const, that way you example above of an array would work for any=type T. it could be used the same way in generic programming. --Yigalafter thinking about the above here are my thoughts: the problem is trying to apply a single rule to two very different concepts, so either way you get some type of a compromise. so why not just realize we have a duality in D and plan accordingly. thus instead=of the current rule which states: for every type T, const(T) means that all of T is const and from it derived the rule that const T =3D const(T) and replace it with: if T has value semantics (primitive, union, struct, enum, ..) than the=above rule applies. else, T is a reference type (a class) and const(T) means _only_ that the instance data is const, and its reference is _not_. what we get is that const(T)=3Dconst T only for value types. now, instead of my proposed "bound" keyword, let's just use final whic=his already a reserved keyword. final will always imply const too because of const transitivity (it'll=be a superset of const). that way for value types the following are identical: const(S) s; final S s; final const S s; // could be reported by the compiler as redundant const S s; and for reference types (classes) we get the following behavior: const(C) c =3D new C(); // mutable ref to const data const C c =3D new C(); // same as above (compiler could issue a warnin=gfor lack of parens) final const(C) c =3D new C(); // const ref to const data final const C c =3D new C(); //same as above final C c =3D new C(); //same as above no issues with const(int) being mutable and other unintuitive syntaxes=.generic programming - you can choose to use const(T)/const T for a weaker input condition or a final T for a stronger input condition tha=twill enforce full constancy of T for all types. for function definitions: 'in' should be mapped to const as defined above, and as I suggested before the compiler should choose if he pass=esthe parameter by value or by reference with optional control of that b=ythe user (for system programming..) also it could be worthwhile to make in the default. D community - what do you think? am I totally wrong or is it a sane an=dmore powerful solution to const? -- YigalFirst problem I see is that it does not take into account D's two types = of const - const and invariant. -- Simen
Mar 08 2008
Simen Kjaeraas wrote:On Thu, 06 Mar 2008 20:21:32 +0100, Yigal Chripun <yigal100 gmail.com> wrote:why not? I only used const to simplify. you can add variant with the same rules. let's say that final defaults to const, BUT, if you can also use: --- final invariant(C) c= new C(); // a const ref to invariant data --- since both mutable and invariant implicitly cast to const, the above is sufficient. invariant data will contain invariant pointers only but they'll convert to const whenever necessary. also perhaps it's worth considering to remove the const T syntax from the language and always require parens. it will simplify usage and remove confusion for C++ programmers, because now both the syntax and the semantics are different so you can't confuse the meaning of const T. -- YigalYigal Chripun wrote:First problem I see is that it does not take into account D's two types of const - const and invariant. -- SimenJanice Caron wrote:after thinking about the above here are my thoughts: the problem is trying to apply a single rule to two very different concepts, so either way you get some type of a compromise. so why not just realize we have a duality in D and plan accordingly. thus instead of the current rule which states: for every type T, const(T) means that all of T is const and from it derived the rule that const T = const(T) and replace it with: if T has value semantics (primitive, union, struct, enum, ..) than the above rule applies. else, T is a reference type (a class) and const(T) means _only_ that the instance data is const, and its reference is _not_. what we get is that const(T)=const T only for value types. now, instead of my proposed "bound" keyword, let's just use final which is already a reserved keyword. final will always imply const too because of const transitivity (it'll be a superset of const). that way for value types the following are identical: const(S) s; final S s; final const S s; // could be reported by the compiler as redundant const S s; and for reference types (classes) we get the following behavior: const(C) c = new C(); // mutable ref to const data const C c = new C(); // same as above (compiler could issue a warning for lack of parens) final const(C) c = new C(); // const ref to const data final const C c = new C(); //same as above final C c = new C(); //same as above no issues with const(int) being mutable and other unintuitive syntaxes. generic programming - you can choose to use const(T)/const T for a weaker input condition or a final T for a stronger input condition that will enforce full constancy of T for all types. for function definitions: 'in' should be mapped to const as defined above, and as I suggested before the compiler should choose if he passes the parameter by value or by reference with optional control of that by the user (for system programming..) also it could be worthwhile to make in the default. D community - what do you think? am I totally wrong or is it a sane and more powerful solution to const? -- YigalOn 20/02/2008, Yigal Chripun <yigal100 gmail.com> wrote:As I've already said: it's only a start of an idea and should be further refined. that said, you are right that it's superfluous in the example above. I've mainly suggested a new keyword and the idea to seperate the two use cases of const. I'm not sure if the "bound" property should be transitive or not ( i suggested that it is but all options should be explored..) and it all depends on what semantics you want to achieve. maybe (probably) bound should also imply const on the referred data and const would imply all refs inside the data object to be bound. another tweak that can be done: intead of an error, if you apply bound to a value type (like a primitive) the compiler implicitly "casts" that to a const, that way you example above of an array would work for any type T. it could be used the same way in generic programming. --Yigalbound const Class c4 = new Class(); // bound (ie const) ref to const dataWouldn't the word "const" be superfluous in that example, since constancy is transitive? (If the reference is constant, the data /must/ be). It's an interesting idea, but I think, in general, if the compiler sees an array like const(T)[] x; then it has to mean that the array's contents are not modifiable. That rule shouldn't depend on T, it should simply be true always. Ditto all other collections.
Mar 08 2008
On 09/03/2008, Yigal Chripun <yigal100 gmail.com> wrote:also perhaps it's worth considering to remove the const T syntax from the language and always require parens.The bad news is, that would also disallow const x = 3; and const { int x = 3; int y = 4; } The problem here is that "const" is an "attribute" in the grammar, and therefore can be used anywhere "public", "static", "auto", "version(X)", and so on can be used. Changing that would be a major upheaval. The simplest route to re-assignable const reference is probably a template solution. In fact, if you look at the change log for D2.012, you'll see that it says: "std.typecons: added undocumented Rebindable in preparation for opImplicitCast." So, that sounds to me like as the language permits (as soon as we have opImplicitCast) we'll also have Rebindable!(T) - a rebindable class reference. We just need to hang on a little bit longer.
Mar 08 2008
Janice Caron wrote:On 09/03/2008, Yigal Chripun <yigal100 gmail.com> wrote:since all programming languages are Turing complete you can write code to emulate what ever you want. With that line of thought you don't need const as part of D either, as you can write template code to emulate that feature. yet, it is in the D language. the point is, that while Rebindable!(T) will solve the problem from an implementation point of view, it still remains a hack IMHO that shows a lacking type system. the fact that you can solve it with a template doesn't mean that it's a better, cleaner design, and while taste is a personal thing, for me that makes D look ugly and unpolished. Walter's enum solution to the manifest constant is a similar issue, while it does solve the problem, it remains IMHO an ugly hack. all I wanted to point out is that i want a more elegant solution, and that sometimes implementation driven design makes for bad decisions. while manifest constants and enums probably should have the same implementation (for example), that does not imply that the interface should be the same too. </rant> --Yigalalso perhaps it's worth considering to remove the const T syntax from the language and always require parens.The bad news is, that would also disallow const x = 3; and const { int x = 3; int y = 4; } The problem here is that "const" is an "attribute" in the grammar, and therefore can be used anywhere "public", "static", "auto", "version(X)", and so on can be used. Changing that would be a major upheaval. The simplest route to re-assignable const reference is probably a template solution. In fact, if you look at the change log for D2.012, you'll see that it says: "std.typecons: added undocumented Rebindable in preparation for opImplicitCast." So, that sounds to me like as the language permits (as soon as we have opImplicitCast) we'll also have Rebindable!(T) - a rebindable class reference. We just need to hang on a little bit longer.
Mar 09 2008
"Sergey Gromov" wroteSteven Schveighoffer wrote:That is the usage I am referring to. I'll spell it out in English: class C means that C is equivalent to a "reference to a some data" that compromises the class that follows the given definition. If I interpret const(C) as constant C, or substituting for the english definition of C, a constant reference to some data, it is natural to assume that both the data AND the reference are const. It does not make intuitive sense that const(C) means reference to some constant data, where the const applies to the data, but not the reference, even though the reference is in C. It makes even less sense that const(int) means mutable int. X * means a pointer to X, so const(X) * means a pointer to a constant X, that makes sense. But since classes do not have the reference separated in syntax, there is no way to bring that piece of it outside the parentheses. This is why we need a new syntax, to make the definition clear and unambiguous. Your intuition may vary from 99% of us here, but that doesn't really matter. Your solution isn't intuitive, it is confusing, it would hinder the adoption of D 2. Walter is trying to attract as many coders as possible, not just you ;) -Steve"Sergey Gromov" wroteThe traditional usage of parentheses is this: foo(x). This means that a function foo is applied to its argument x, and not applied to everything else. You are probably talking about some different tradition. Please clarify.If you create a generic algorithm which works with T, and declare something as const(T) t; then you effectively assert that you're going to replace t with different other Ts, but promise to keep integrity of a referenced T intact, if anything is referenced at all. This means that for int, which is not referencing anything, const(int) t; is completely and safely equivalent to int t; without breaking any contracts of your algorithm. Please provide an example where "const(int) x;" absolutely must mean "const int x;" for a generic algorithm to work properly.Sergey, I am not arguing that the functionality that you wish to have is invalid. In fact, I would have been ok with that syntax, and understood it once it was explained thoroughly. But I have to say that I agree with Janice and Walter on this one, it was very confusing. It just goes against the traditional usage of parentheses. The idea is correct, the syntax is confusing. Find another syntax.
Feb 20 2008
Steven Schveighoffer <schveiguy yahoo.com> wrote:At least, now I understand why we can't understand each other. For a declaration, C x; you imply reference in C, and I imply reference in x. const(C) x; // text written const(C) (ref x); // my understanding const(C ref) x; // your understanding No wonder we can't agree. Now I'm curious why the difference. To me, C is a class, and x is a reference. Why it's different for you ? -- SnakEThe traditional usage of parentheses is this: foo(x). This means that a function foo is applied to its argument x, and not applied to everything else. You are probably talking about some different tradition. Please clarify.That is the usage I am referring to. I'll spell it out in English: class C means that C is equivalent to a "reference to a some data" that compromises the class that follows the given definition.
Feb 20 2008
"Sergey Gromov" wroteSteven Schveighoffer wrote:Arghh! I can't type today! Compromises? :)The traditional usage of parentheses is this: foo(x). This means that a function foo is applied to its argument x, and not applied to everything else. You are probably talking about some different tradition. Please clarify.That is the usage I am referring to. I'll spell it out in English: class C means that C is equivalent to a "reference to a some data" that compromises the class that follows the given definition.At least, now I understand why we can't understand each other. For a declaration, C x; you imply reference in C, and I imply reference in x. const(C) x; // text written const(C) (ref x); // my understanding const(C ref) x; // your understanding No wonder we can't agree. Now I'm curious why the difference. To me, C is a class, and x is a reference. Why it's different for you ?C is a class reference. There is no way to express the type of the class data, because D doesn't support value-type classes. I.e. there is no way to separate the reference from C. Whenever you see: class C {} in D, It's like the equivalent in C++ of class _C {}; typedef _C& C; But in D there is no way to get at the type _C. And D class references are rebindable. In D, the type never is in the variable, it's always in the type declaration. -Steve
Feb 20 2008