digitalmars.D.learn - readonly?
- Namespace (18/18) Jul 10 2012 Maybe D need's a readonly keyword.
- Simen Kjaeraas (34/52) Jul 10 2012 If Bar is a class, use std.typecons.Rebindable.
- Tobias Pankrath (2/20) Jul 10 2012 const(T)* ?
- Namespace (1/2) Jul 10 2012 Example?
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (17/19) Jul 10 2012 class Bar
- Namespace (1/17) Jul 10 2012 Hmm... That's good. Thanks.
- Timon Gehr (2/22) Jul 10 2012 This escapes a stack reference.
- Tobias Pankrath (1/2) Jul 10 2012 Ins't b supposed to be allocated on the heap?
- Jonathan M Davis (4/7) Jul 10 2012 The object is. The reference is not. &b is taking the address of the
- David Nadlinger (5/7) Jul 10 2012 The Bar instance is, but the pointer to it is not. Making _b a
- Tobias Pankrath (6/15) Jul 11 2012 Bar b = new Bar;
- Jonathan M Davis (9/15) Jul 11 2012 I don't think that you can. It's a reference, not a pointer. And if you ...
- Artur Skawina (23/38) Jul 11 2012 Yeah, unfortunately.
- David Nadlinger (4/13) Jul 11 2012 Why would it be broken? Bar intrinsically is a reference type, so
- Tobias Pankrath (4/18) Jul 11 2012 The languages conflates reference and instance type for classes.
- David Nadlinger (8/12) Jul 11 2012 This is not an inconsistency, but by design. Classes
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (14/15) Jul 11 2012 Most other operations act on the object:
- Jonathan M Davis (39/58) Jul 11 2012 It's the fact that in the type system B is a reference to the class name...
- Artur Skawina (10/21) Jul 11 2012 Because it doesn't let you have a real pointer to a class.
- David Nadlinger (6/14) Jul 11 2012 What is a »real pointer«? Class references are really just
- Artur Skawina (23/36) Jul 11 2012 A "real pointer" is a pointer.
- Jonathan M Davis (7/10) Jul 11 2012 You'd also lose polymorphism, which you don't with Rebindable. In D,
- Jonathan M Davis (117/118) Jul 11 2012 Easily.
- Artur Skawina (46/185) Jul 12 2012 You misunderstand the "current (broken) behavior" part - it is about
- Jesse Phillips (2/5) Jul 11 2012 https://github.com/D-Programming-Language/dmd/pull/3
Maybe D need's a readonly keyword. Sometimes i have a class which can take an object from everywhere to store it. So it can not be const, because i didn't just initialized it with a ctor. But i don't want to change the object, i only want to read or call const methods. What now? I'd suggest a readonly keyword for that. [code] class Foo { readonly: Bar _b; public: void SetBar(readonly Bar b) { _b = b; } } [/code] Or has D an alternative?
Jul 10 2012
On Tue, 10 Jul 2012 21:27:54 +0200, Namespace <rswhite4 googlemail.com> wrote:Maybe D need's a readonly keyword. Sometimes i have a class which can take an object from everywhere to store it. So it can not be const, because i didn't just initialized it with a ctor. But i don't want to change the object, i only want to read or call const methods. What now? I'd suggest a readonly keyword for that. [code] class Foo { readonly: Bar _b; public: void SetBar(readonly Bar b) { _b = b; } } [/code] Or has D an alternative?If Bar is a class, use std.typecons.Rebindable. Otherwise, it's hairier. What should readonly mean? From what I see, it provides const access, and is reassignable. This is easily implemented in user code today: import std.traits; struct Readonly( T ) { private T payload; this( Unqual!T value ) { payload = value; } auto opAssign( const T value ) { payload = cast()value; return this; } property const(T) get( ) const { return payload; } alias get this; } unittest { struct S { int n; void foo() {} void bar() const {} } Readonly!S a; a = S( 3 ); assert( a.n == 3 ); assert( !__traits( compiles, a.n = 4 ) ); assert( !__traits( compiles, a.foo() ) ); assert( __traits( compiles, a.bar() ) ); }
Jul 10 2012
On Tuesday, 10 July 2012 at 19:27:56 UTC, Namespace wrote:Maybe D need's a readonly keyword. Sometimes i have a class which can take an object from everywhere to store it. So it can not be const, because i didn't just initialized it with a ctor. But i don't want to change the object, i only want to read or call const methods. What now? I'd suggest a readonly keyword for that. [code] class Foo { readonly: Bar _b; public: void SetBar(readonly Bar b) { _b = b; } } [/code] Or has D an alternative?const(T)* ?
Jul 10 2012
On 07/10/2012 03:53 PM, Namespace wrote:class Bar {} class Foo { const(Bar) * _b; void SetBar(const(Bar) * b) { _b = b; } } void main() { auto b = new Bar(); auto f = new Foo(); f.SetBar(&b); } Aliconst(T)* ?Example?
Jul 10 2012
class Bar {} class Foo { const(Bar) * _b; void SetBar(const(Bar) * b) { _b = b; } } void main() { auto b = new Bar(); auto f = new Foo(); f.SetBar(&b); } AliHmm... That's good. Thanks.
Jul 10 2012
On 07/11/2012 12:58 AM, Ali Çehreli wrote:On 07/10/2012 03:53 PM, Namespace wrote:This escapes a stack reference.class Bar {} class Foo { const(Bar) * _b; void SetBar(const(Bar) * b) { _b = b; } } void main() { auto b = new Bar(); auto f = new Foo(); f.SetBar(&b); } Aliconst(T)* ?Example?
Jul 10 2012
This escapes a stack reference.Ins't b supposed to be allocated on the heap?
Jul 10 2012
On Wednesday, July 11, 2012 08:34:28 Tobias Pankrath wrote:The object is. The reference is not. &b is taking the address of the reference, not the object. - Jonathan M DavisThis escapes a stack reference.Ins't b supposed to be allocated on the heap?
Jul 10 2012
On Wednesday, 11 July 2012 at 06:34:29 UTC, Tobias Pankrath wrote:The Bar instance is, but the pointer to it is not. Making _b a Rebindable instead of using a pointer (to what effectively is a pointer to the real object) should help. DavidThis escapes a stack reference.Ins't b supposed to be allocated on the heap?
Jul 10 2012
On Wednesday, 11 July 2012 at 06:48:59 UTC, David Nadlinger wrote:On Wednesday, 11 July 2012 at 06:34:29 UTC, Tobias Pankrath wrote:Bar b = new Bar; auto b2 = &b; // type of b2 is Bar* So does it meen, that a pointer of type Bar* does not point to the real object? How do I get such a pointer then and which type does it have?The Bar instance is, but the pointer to it is not. Making _b a Rebindable instead of using a pointer (to what effectively is a pointer to the real object) should help. DavidThis escapes a stack reference.Ins't b supposed to be allocated on the heap?
Jul 11 2012
On Wednesday, July 11, 2012 09:00:26 Tobias Pankrath wrote:Bar b = new Bar; auto b2 = &b; // type of b2 is Bar* So does it meen, that a pointer of type Bar* does not point to the real object?It's a pointer to a reference, not to the object.How do I get such a pointer then and which type does it have?I don't think that you can. It's a reference, not a pointer. And if you _can_ do it, I bet that it's not at all pretty. References are _not_ intended to be treated the same as pointers. They're similar, but they're fundamentally different. And instances of classes are intended to be referred to by references, _not_ be pointed to by pointers. Rebindable is the correct solution to this "readonly" issue. - Jonathan M Davis
Jul 11 2012
On 07/11/12 09:00, Tobias Pankrath wrote:On Wednesday, 11 July 2012 at 06:48:59 UTC, David Nadlinger wrote:Yeah, unfortunately. Can anybody think of a reason to keep the current (broken) behavior?On Wednesday, 11 July 2012 at 06:34:29 UTC, Tobias Pankrath wrote:Bar b = new Bar; auto b2 = &b; // type of b2 is Bar* So does it meen, that a pointer of type Bar* does not point to the real object?The Bar instance is, but the pointer to it is not. Making _b a Rebindable instead of using a pointer (to what effectively is a pointer to the real object) should help. DavidThis escapes a stack reference.Ins't b supposed to be allocated on the heap?How do I get such a pointer then and which type does it have?You can use something like this: static struct ClassPtr(C) if (is(C==class)) { // '__cp' is not the same as what the compiler currently considers a class // pointer; it is used here as a container for the reference. This adds the // missing level of indirection, which allows for the necessary different // (but still compatible) types. private C* __cp; pure: safe: nothrow: trusted this(C o) { __cp = cast(C*)o; } trusted C opAssign(C o) { __cp = cast(C*)o; return o; } trusted property C get() { return cast(C)__cp; } trusted property const(C) get() const { return cast(C)__cp; } alias get this; } // Eg: class Bar {} class Foo { ClassPtr!(const Bar) _b; void SetBar(const Bar b) { _b = b; } } And - no - this shouldn't be necessary. artur
Jul 11 2012
On Wednesday, 11 July 2012 at 08:56:39 UTC, Artur Skawina wrote:On 07/11/12 09:00, Tobias Pankrath wrote:Why would it be broken? Bar intrinsically is a reference type, so Bar* is a pointer to a reference. DavidBar b = new Bar; auto b2 = &b; // type of b2 is Bar* So does it meen, that a pointer of type Bar* does not point to the real object?Yeah, unfortunately. Can anybody think of a reason to keep the current (broken) behavior?
Jul 11 2012
On Wednesday, 11 July 2012 at 09:49:43 UTC, David Nadlinger wrote:On Wednesday, 11 July 2012 at 08:56:39 UTC, Artur Skawina wrote:The languages conflates reference and instance type for classes. See here http://dpaste.dzfl.pl/a55ad2b6 . I wouldn't say this should change but it is a minor inconsistency I just stumbled on.On 07/11/12 09:00, Tobias Pankrath wrote:Why would it be broken? Bar intrinsically is a reference type, so Bar* is a pointer to a reference. DavidBar b = new Bar; auto b2 = &b; // type of b2 is Bar* So does it meen, that a pointer of type Bar* does not point to the real object?Yeah, unfortunately. Can anybody think of a reason to keep the current (broken) behavior?
Jul 11 2012
On Wednesday, 11 July 2012 at 10:00:33 UTC, Tobias Pankrath wrote:The languages conflates reference and instance type for classes. See here http://dpaste.dzfl.pl/a55ad2b6 . I wouldn't say this should change but it is a minor inconsistency I just stumbled on.This is not an inconsistency, but by design. Classes intrinsically are reference types, there isn't something like an »instance type« for them, which helps avoiding things like the slicing problem in C++. Yes, in D, types are always only either value types (structs) or polymorphic reference types (classes), but I fail to see anything inconsistent here. David
Jul 11 2012
On 07/11/2012 08:52 AM, David Nadlinger wrote:I fail to see anything inconsistent here.Most other operations act on the object: class B { // ... } auto b = new B(); ++b; // on the object b > b; // on the object // etc. &b; // on the reference That can be seen as an inconsistency. Perhaps it is that the non-overridable operators are on the class reference? Ali
Jul 11 2012
On Wednesday, July 11, 2012 09:51:37 Ali Çehreli wrote:On 07/11/2012 08:52 AM, David Nadlinger wrote:It's the fact that in the type system B is a reference to the class named B, _not_ the class itself. ++b operates on the object itself, because it's not legal to increment a reference. Such an operation makes no sense. Almost all operations get forwarded to the object just like using . with a pointer gets forwarded to the pointee. One of the few operations which makes sense on the reference itself is &, since it gives you the address of the reference. On the other hand, it makes no sense to take the address of the object itself, since there is _no way_ in the type system to refer to that object, and the type system purposefully makes it so that you don't and can't mess with class objects directly, since it avoids problems such as object slicing. So, while it may seem odd at first that & operates on the reference itself rather than the object, remember that the fact that a reference uses a pointer is an implementation detail which is _not_ represented in the type at all. Think of it like this: struct S { //opDispatch defined here and //all overloaded operators defined here to forward to *ptr... private: C* ptr; } S s; &s would naturally refer to s, not ptr, and there's no way to access ptr directly. What engenders so much confusion is that in D's type system, S is referred to as C, so you essentially get struct C { ... private: C* ptr; } C c; where C refers to the struct everywhere except with ptr, which refers to the actual class object. So, while some of the behaviors with regards to classes may seem odd at first, they're actually _very_ consistent with everything else. - Jonathan M DavisI fail to see anything inconsistent here.Most other operations act on the object: class B { // ... } auto b = new B(); ++b; // on the object b > b; // on the object // etc. &b; // on the reference That can be seen as an inconsistency. Perhaps it is that the non-overridable operators are on the class reference?
Jul 11 2012
On 07/11/12 11:49, David Nadlinger wrote:On Wednesday, 11 July 2012 at 08:56:39 UTC, Artur Skawina wrote:Because it doesn't let you have a real pointer to a class. The obvious alternative would be: auto r = new Bar(); // reference Bar* p = r; // pointer to Bar; ref implicitly converts to pointer. auto pr = &r; // typeof(pr)==Bar** ; can't do better w/o ref types. So, does the current scheme have any advantages? (currently, the second example is illegal and the last '&r' expression results in 'Bar *') arturOn 07/11/12 09:00, Tobias Pankrath wrote:Why would it be broken? Bar intrinsically is a reference type, so Bar* is a pointer to a reference.Bar b = new Bar; auto b2 = &b; // type of b2 is Bar* So does it meen, that a pointer of type Bar* does not point to the real object?Yeah, unfortunately. Can anybody think of a reason to keep the current (broken) behavior?
Jul 11 2012
On Wednesday, 11 July 2012 at 10:05:40 UTC, Artur Skawina wrote:Because it doesn't let you have a real pointer to a class.What is a »real pointer«? Class references are really just pointers, in a way – you can cast them to void*.The obvious alternative would be: auto r = new Bar(); // reference Bar* p = r; // pointer to Bar; ref implicitly converts to pointer. auto pr = &r; // typeof(pr)==Bar** ; can't do better w/o ref types. So, does the current scheme have any advantages?When discussing a language change, the question should always be: Does the _new_ scheme have any advantages? David
Jul 11 2012
On 07/11/12 17:54, David Nadlinger wrote:On Wednesday, 11 July 2012 at 10:05:40 UTC, Artur Skawina wrote:A "real pointer" is a pointer. Class refs are basically pointers, but with some extra limitations and syntax sugar. The key distinction is that you can implement references on top of pointers, but the opposite isn't true. Hence refs are not "real" pointers. Casting refs in order to extract their value /is/ possible, but that gets ugly and dangerous (if not actually 'undefined'); the ClassPtr type that i posted in this thread is a good example - it may be just ~6 lines of code, but that's six line of code that everybody that's reading or using it must analyze, before determining if it's correct and sane. (and, yes, it's not perfect, eg it doesn't even try to handle immutable - simply because I had no need for that so far)Because it doesn't let you have a real pointer to a class.What is a »real pointer«? Class references are really just pointers, in a way – you can cast them to void*.Yeah, except when the old scheme was an accident, which I have to assume is the case here. Hence the questions, just in case the behavior was in fact chosen deliberately and I'm missing something. The advantages of having pointers to classes? Eg solving the problem that triggered this thread w/o hacks like ClassPtr (Rebindable is an even worse hack). [1] Not to mention that the current model is extremely misleading; consider that three different people got it wrong in this thread alone... artur [1] "direct" pointers, going via a ref obviously works, even if less efficient. Which brings us back to the question - are there any advantages of /that/ scheme?The obvious alternative would be: auto r = new Bar(); // reference Bar* p = r; // pointer to Bar; ref implicitly converts to pointer. auto pr = &r; // typeof(pr)==Bar** ; can't do better w/o ref types. So, does the current scheme have any advantages?When discussing a language change, the question should always be: Does the _new_ scheme have any advantages?
Jul 11 2012
On Wednesday, July 11, 2012 23:09:17 Artur Skawina wrote:The advantages of having pointers to classes? Eg solving the problem that triggered this thread w/o hacks like ClassPtr (Rebindable is an even worse hack). [1]You'd also lose polymorphism, which you don't with Rebindable. In D, references are polymorphic. Pointers are not. You really don't want to be using a pointer to a class. D was designed with the idea that classes would accessed through references, not pointers, and the related features are all designed around that. - Jonathan M Davis
Jul 11 2012
On Wednesday, July 11, 2012 10:56:23 Artur Skawina wrote:Can anybody think of a reason to keep the current (broken) behavior?Easily. Making Object* point to the object itself rather than the reference would be so broken that it's not even funny. I can understand why you would think that such a change should be made, but that's only because you haven't thought through all of the consequences of that. It's all wrapped up in the very reason why Rebindable is in the library rather than being built into the language. For starters, if you have class C {} C c; the type of c is C. C is a reference to the class named C. It does _not_ mean the same thing as the C in the class declaration at all. If it were a struct rather than a class, it would be equivalent to C* (save for the fact that a reference and a pointer aren't quite the same). So, _everywhere_ in the type system that you see C, it's really C*, _not_ C as in the class C. There is _no way_ in the type system to refer to the class itself. So, making C* be a pointer to the object rather than the reference isn't even representable in Walter tried to get around this to implement Rebindable in the language and gave up on it. It may be possible, but it's _ugly_ if it is. There are all kinds of practical side effects for this. For instance, if you had class D : C {} C c; C* cPtr = &c; and C* was a pointer to the class itself, then it would almost be like doing C* c; C* cPtr = &c; which makes no sense at all. It also introduces object slicing - as in the type of slicing that C++ has when you assign a derived object to a base class object which is on the stack. In C++, D d; C c = d; results in the D portion of d being chopped off, potentially putting it in an invalid state, and almost certainly isn't what you wanted to do. D avoids this by requiring that polymorphic objects (classes) be on the heap. But if C* referred to the object itself, it becomes a probem again. C c = new C; C* cPtr = &c; *cPtr = new D; Since cPtr was a pointer to the object, *cPtr would be the object itself, and so the D object would be assigned to the C object and get sliced, just like in the C++ example. In additon, making Object* be a pointer to the object itself would make dealing with pointers to local objects _very_ inconsistent. Take this for example void func(T)(T* t, T value) { *t = value; } int i; func(&i, 7); C c = getC(); func(&c, new C); When func is called with &i, it sets i to 7. But when it's called with &c, it doesn't set c. It sets what c refers to. This means that instead of changing the local variable c, you've changed an object on the heap which other references could refer to, and now instead of just affecting the local reference, _every_ reference is affected. This is _completely_ different from how it works with &i. It's more in like with how it would work if you had int* iPtr = getIntPtr(); func(&iPtr, new int); and since C is essentially equivalent to C*, it would then be impossible to pass the reference itself to func to be set. It would also make it so that taking a pointer for a parameter was very different from taking ref or out for classes, when it's nearly identical for everything else. void refFunc(T)(ref T t, T value) { t = value; } int i; refFunc(i, 7); C c = getC(); refFunc(c, new C); With your suggestion, this code operates identically for i but does something completely different for c. Now, instead of setting the object, it's setting the reference. AAs would also be very broken if Object* pointed to the object rather than the reference. Take this code: int[string] aa; int* intPtr = "hello" in aa; C[string] bb; C* cPtr = "hello" in bb; With aa, you get a pointer to the value which is at the key "hello". With bb, you get a pointer to the object which the value at "hello" refers to. So, once again, setting *cPtr sets the object rather than the reference, and slicing becomes a problem. On top of that, what happens with null? Right now, you can do bb["hello"] = null; C* v1 = "hello" in bb; C* v2 = "world" in bb; The fact that v1 is non-null tells you that "hello" is in bb, and the fact that v2 is null tells you that "world" isn't in bb. You can then dereference v1 and get at the value which is at "hello", which is null. But what happens when C* nows points to the object rather than the reference? It becomes impossible to distinguish between the case when the key isn't in the AA and when the value at that key is null. You could fix that by making it so that C[string] bb; was implicitly C*[string] bb; but then the type that in returns would have to be C**, making it so that Objects behaved differently with AAs than every other type, since in all other cases with T[U], in returns T*, not T**. I could go on, but this post is already ridiculously long. The point is that the type system is built around the fact that class variables are _always_ references and that there is no way to refer to such an object directly. If you start referring to the object directly, things break. The type system just does not support that, and making &c give you pointer to the object rather than the reference would make it _completely_ inconsistent with the rest of the language, much as it might seem otherwise at first. You just have to realize that whenever you see Object (or any other class type) used, it's a reference, _not_ the type of the object itself, and that it's impossible (within the type system) to refer to the object itself, so the behavior of &c is _completely_ consistent with the rest of the language. - Jonathan M Davis
Jul 11 2012
On 07/12/12 01:09, Jonathan M Davis wrote:On Wednesday, July 11, 2012 10:56:23 Artur Skawina wrote:You misunderstand the "current (broken) behavior" part - it is about what 'C*' is, it is not at all about class references.Can anybody think of a reason to keep the current (broken) behavior?Easily.Making Object* point to the object itself rather than the reference would be so broken that it's not even funny. I can understand why you would think that such a change should be made, but that's only because you haven't thought through all of the consequences of that. It's all wrapped up in the very reason why Rebindable is in the library rather than being built into the language. For starters, if you have class C {} C c; the type of c is C. C is a reference to the class named C. It does _not_ mean the same thing as the C in the class declaration at all. If it were a struct rather than a class, it would be equivalent to C* (save for the fact that a reference and a pointer aren't quite the same). So, _everywhere_ in the type system that you see C, it's really C*, _not_ C as in the class C. There is _no way_ in the type system to refer to the class itself. So, making C* be a pointer to the object rather than the reference isn't even representable in the type system.Of course it is - you even say it above: "_everywhere_ in the type system that you see C, it's really C*". But instead of considering the implications and required semantics, you are making several assumptions, which are wrong. For example - let 'C' be a class, then: 'new C' must return a reference to C, not a pointer; dereferencing a 'C*' pointer should of course not be valid.There are all kinds of practical side effects for this. For instance, if you had class D : C {} C c; C* cPtr = &c; and C* was a pointer to the class itself, then it would almost be like doing C* c; C* cPtr = &c; which makes no sense at all.This is actually what effectively happens with the *current* model, it in deed makes little sense, and is the reason for my "why?" questions...It also introduces object slicing - as in the type of slicing that C++ has when you assign a derived object to a base class object which is on the stack. In C++, D d; C c = d; results in the D portion of d being chopped off, potentially putting it in anD and C (in D) are references - there's no problem. I have no idea why you think classes would be value types.invalid state, and almost certainly isn't what you wanted to do. D avoids this by requiring that polymorphic objects (classes) be on the heap. But if C* referred to the object itself, it becomes a probem again. C c = new C; C* cPtr = &c; *cPtr = new D; Since cPtr was a pointer to the object, *cPtr would be the object itself, and so the D object would be assigned to the C object and get sliced, just like in the C++ example.Dereferencing a class pointer has to be illegal, i thought that was obvious and not needed to be spelled out. It's a simple and easily understandable rule. So '*cPtr' wouldn't be valid - there is no problem.In additon, making Object* be a pointer to the object itself would make dealing with pointers to local objects _very_ inconsistent. Take this for example void func(T)(T* t, T value) { *t = value; } int i; func(&i, 7); C c = getC(); func(&c, new C); When func is called with &i, it sets i to 7. But when it's called with &c, it doesn't set c. It sets what c refers to. This means that instead of changing'*t' would not compile for a T*==C* (when the latter means a direct pointer to the instance) ; see above. Whether that should compile, in the model i gave as an example, is a different question - there the call is 'func(C**, C)' which results in 'C* = implicit_cast(C*)C' -- this modifies the reference. I can see arguments for disallowing this, but then the 'rebindable' problem would be back, so I'd lean toward keeping it legal.the local variable c, you've changed an object on the heap which other references could refer to, and now instead of just affecting the local reference, _every_ reference is affected. This is _completely_ different from how it works with &i. It's more in like with how it would work if you had int* iPtr = getIntPtr(); func(&iPtr, new int); and since C is essentially equivalent to C*, it would then be impossible to pass the reference itself to func to be set.That's why I have '&C_instance' result in 'C**'. not 'C*'. Yes, it means classes are treated differently -- but they *already* are. Yes, it's *only* about the type, most (ie all desirable) semantics of references are kept.It would also make it so that taking a pointer for a parameter was very different from taking ref or out for classes, when it's nearly identical for everything else. void refFunc(T)(ref T t, T value) { t = value; } int i; refFunc(i, 7); C c = getC(); refFunc(c, new C); With your suggestion, this code operates identically for i but does something completely different for c. Now, instead of setting the object, it's setting the reference.Huh? There are no (explicit) pointers involved here, there's no difference. I think you didn't actually read my example carefully enough, as you keep bringing up things that nobody suggested, and which wouldn't make any sense.AAs would also be very broken if Object* pointed to the object rather than the reference. Take this code: int[string] aa; int* intPtr = "hello" in aa; C[string] bb; C* cPtr = "hello" in bb; With aa, you get a pointer to the value which is at the key "hello". With bb, you get a pointer to the object which the value at "hello" refers to. So, once again, setting *cPtr sets the object rather than the reference, and slicing becomes a problem. On top of that, what happens with null? Right now, you can do bb["hello"] = null; C* v1 = "hello" in bb; C* v2 = "world" in bb; The fact that v1 is non-null tells you that "hello" is in bb, and the fact that v2 is null tells you that "world" isn't in bb. You can then dereference v1 and get at the value which is at "hello", which is null. But what happens when C* nows points to the object rather than the reference? It becomes impossible to distinguish between the case when the key isn't in the AA and when the value at that key is null. You could fix that by making it so that C[string] bb; was implicitly C*[string] bb; but then the type that in returns would have to be C**, making it so that Objects behaved differently with AAs than every other type, since in all other cases with T[U], in returns T*, not T**.The AA 'in' operator is one of the odder ones, but there's no problem. Remember the '&C => C**' rule? 'typeof("abc" in bb)==C**'. Maybe it's easier to understand when you realize that what happens underneath is equivalent to declaring a 'C*[string] bb'.(within the type system) to refer to the object itself, so the behavior of &c is _completely_ consistent with the rest of the language.Nope. But the question was if there is any advantage to the current model? And so far I've seen none mentioned. Note that one alternative is to basically treat 'C*' similarly to a reference to C, which means there are no slicing or polymorphism issues, as the obvious extra restrictions on such a type take care of things. This new model would be much saner, while allowing things that are currently not (cleanly) possible. I'm really just wondering if there was some real reason behind the design, or if it was just an accident, because nobody considered the consequences - like in the case of so many other D features. This isn't about changing things now (at least not short term), it's about future directions. artur
Jul 12 2012
On Tuesday, 10 July 2012 at 19:27:56 UTC, Namespace wrote:Maybe D need's a readonly keyword. [...] Or has D an alternative?https://github.com/D-Programming-Language/dmd/pull/3
Jul 11 2012