digitalmars.D.learn - Immutable objects and constructor ?
- chmike (51/51) May 20 2016 I'm implementing the flyweight pattern. It means that I have a
- Kagamin (3/9) May 20 2016 Use mutable class.
- chmike (3/13) May 20 2016 Thank you very much for the fast and very helpful reply. I'll try
- chmike (32/32) May 20 2016 The error message is gone, but I now have another compilation
- Marc =?UTF-8?B?U2Now7x0eg==?= (7/40) May 20 2016 Yes, nested classes have an implicit reference to their parent
- chmike (4/8) May 20 2016 That worked great. Thank you.
- chmike (31/31) May 20 2016 I solved the problem by moving the class Obj definition out of
- Kagamin (4/9) May 20 2016 Sort of possible with a library solution:
- chmike (9/20) May 20 2016 I'm a bit surprized that the language doesn't support this. We
- Jonathan M Davis via Digitalmars-d-learn (37/59) May 20 2016 It has to do with the fact that the type system does not differentiate
- chmike (50/50) May 21 2016 Unfortunately it is not possible to write this
- chmike (4/4) May 21 2016 Since I'm trying to implement a flyweight pattern, the opEqual
- =?UTF-8?Q?Ali_=c3=87ehreli?= (12/16) May 21 2016 You have a capitalization typo. Rebindable is a type template,
- chmike (5/22) May 21 2016 Thank you. I'll start a new thread with the subject "problems
- Mike Parker (14/17) May 20 2016 Consider this:
- Mike Parker (23/35) May 20 2016 I strongly advise you put C++ out of your head when programming D
- Mike Parker (9/20) May 20 2016 I should have addressed this above. This is another of the those
I'm implementing the flyweight pattern. It means that I have a set of object instances representing all the possible values. This allows me to manipulate "values" by simply manipulating references to the instance. Testing "value" equality boils down to simply compare reference value. I hope I can use these immutable instances as case argument of a switch, but I'm not there yet. I have declared an immutable class. ---- immutable interface SomeInfo { ... } immutable class Info : SomeInfo { disable this(); this(int codeValue, string codeName) { codeValue_ = (codeValue * 10) - 113; // some random example computation codeName_ = "Info."~codeName_; } private: int codeValue_; string codeName_; } ---- But when I try to instantiate the class I get an dramatic compilation error: "none of the overloads of '__ctor' are callable using a mutable object, candidates are: " Adding immutable to the constructor doesn't help. How can I initialize the immutable instances of a class ? I have seen it is possible to cast away the immutability. Does it also work for immutable classes ? Could I use an object factory ? How should I do if I would like to use the lazy pattern for initializing some member variables of the instance ? Something like : immutable class Info : SomeInfo { ... string toString() { if (!toString_) synchronize { // make it thread safe if (!toString_) toString_ = format("bla bla %s (%d)", codeName_, codeValue_); } return toString_; } ... private: string toString_; }
May 20 2016
On Friday, 20 May 2016 at 14:06:54 UTC, chmike wrote:But when I try to instantiate the class I get an dramatic compilation error: "none of the overloads of '__ctor' are callable using a mutable object, candidates are: "auto a=new immutable Info(1,"1");How should I do if I would like to use the lazy pattern for initializing some member variables of the instance ?Use mutable class.
May 20 2016
On Friday, 20 May 2016 at 14:40:23 UTC, Kagamin wrote:On Friday, 20 May 2016 at 14:06:54 UTC, chmike wrote:Thank you very much for the fast and very helpful reply. I'll try that.But when I try to instantiate the class I get an dramatic compilation error: "none of the overloads of '__ctor' are callable using a mutable object, candidates are: "auto a=new immutable Info(1,"1");How should I do if I would like to use the lazy pattern for initializing some member variables of the instance ?Use mutable class.
May 20 2016
The error message is gone, but I now have another compilation error message I don't understand. This is what I have in fact interface Info { . . . } class MyInfos { . . . protected: class Obj : Info { . . . } public: static immutable Obj one = new immutable Obj(...); static immutable Obj two = new immutable Obj(...); } I get a compiler error in the two assignments to the static Obj member variables: 'this' is only defined in non-static member functions, not MyInfos Is it related to the fact that the Obj class is encapsulated ? My goal is to be able to write things like this: void main() { Info x1 = MyInfos.one, x2 = MyInfo.two, x3; assert(x3 is null); x3 = x1; assert(x3 is x1); assert(x3 is MyInfo.one); // Use static immutable instance references as case arg in switch switch(x1) { case MyInfo.one: ...; } }
May 20 2016
On Friday, 20 May 2016 at 15:07:53 UTC, chmike wrote:The error message is gone, but I now have another compilation error message I don't understand. This is what I have in fact interface Info { . . . } class MyInfos { . . . protected: class Obj : Info { . . . } public: static immutable Obj one = new immutable Obj(...); static immutable Obj two = new immutable Obj(...); } I get a compiler error in the two assignments to the static Obj member variables: 'this' is only defined in non-static member functions, not MyInfos Is it related to the fact that the Obj class is encapsulated ?Yes, nested classes have an implicit reference to their parent object, which doesn't exist in your case.My goal is to be able to write things like this: void main() { Info x1 = MyInfos.one, x2 = MyInfo.two, x3; assert(x3 is null); x3 = x1; assert(x3 is x1); assert(x3 is MyInfo.one); // Use static immutable instance references as case arg in switch switch(x1) { case MyInfo.one: ...; } }It looks like your don't actually need `Obj` to be a real nested class. Try declaring it as `static Obj : Info { }`. This should work if `Obj`'s methods don't need access to `MyInfo`'s non-static members.
May 20 2016
On Friday, 20 May 2016 at 15:43:28 UTC, Marc Schütz wrote:It looks like your don't actually need `Obj` to be a real nested class. Try declaring it as `static Obj : Info { }`. This should work if `Obj`'s methods don't need access to `MyInfo`'s non-static members.That worked great. Thank you. The only problem left is how I can get mutable references to immutable objects.
May 20 2016
I solved the problem by moving the class Obj definition out of the class MyInfo. I still don't understand why I had to do that. In C++ this would work without problem. I now have interface Info {. . .} class Obj : Info {. . .} class MyInfos { . . . static immutable Obj one = new immutable Obj(...); static immutable Obj two = new immutable Obj(...); . . . } This now compiles without a peep. But I now met another error in my main(). I can't assign the immutable object to a mutable reference. Info x1 = MyInfos.one; Is it possible to define a mutable reference to an immutable instance ? This is confusing and frustrating. In C++ we can write MyInfos { . . . // one is a constant pointer to a constant object of type Obj Obj const * const one; . . . } And in main() Info const * x1 = MyInfos.one; x1 i a modifiable pointer to a constant object of type Info. Is this possible in D ? I couldn't find how to do that.
May 20 2016
On Friday, 20 May 2016 at 16:09:54 UTC, chmike wrote:But I now met another error in my main(). I can't assign the immutable object to a mutable reference. Info x1 = MyInfos.one; Is it possible to define a mutable reference to an immutable instance ?Sort of possible with a library solution: import std.typecons; auto x1 = rebindable(MyInfos.one);
May 20 2016
On Friday, 20 May 2016 at 17:35:01 UTC, Kagamin wrote:On Friday, 20 May 2016 at 16:09:54 UTC, chmike wrote:I'm a bit surprized that the language doesn't support this. We have immutable strings that can be assigned to different variables. Why couldn't we do the same with objects ? This rebindable is not user friendly. I really wish the user could write this Info x = MyInfos.one; I may achieve this if Info is defined as a struct with a single member defined as rebindable.But I now met another error in my main(). I can't assign the immutable object to a mutable reference. Info x1 = MyInfos.one; Is it possible to define a mutable reference to an immutable instance ?Sort of possible with a library solution: import std.typecons; auto x1 = rebindable(MyInfos.one);
May 20 2016
On Friday, May 20, 2016 20:30:22 chmike via Digitalmars-d-learn wrote:On Friday, 20 May 2016 at 17:35:01 UTC, Kagamin wrote:It has to do with the fact that the type system does not differentiate between classes and references to class objects. When you type Object o; that's a reference to a class, not actually a class object, and the same goes for every use of a class. So, while you can have const(int)* ptr; and the compiler understands that, the compiler doesn't have an understanding of the separation of an Object and a reference to an Object, so not only is there no way to represent it syntactically, the compiler can't currently represent it semantically either. This is at least partially a result of making it so that classes inherently live on the heap. It's certainly possible to change it so that we have a way to have tail-const references to classes and so that Rebindable is then unnecessary, but Walter and Andrei don't think that it's worth it, so it hasn't happened. And while Rebindable is kind of ugly, it works just fine. So, the lack of tail-const for classes in the language hasn't really been a blocker for anything, just kind of ugly.On Friday, 20 May 2016 at 16:09:54 UTC, chmike wrote:I'm a bit surprized that the language doesn't support this. We have immutable strings that can be assigned to different variables. Why couldn't we do the same with objects ?But I now met another error in my main(). I can't assign the immutable object to a mutable reference. Info x1 = MyInfos.one; Is it possible to define a mutable reference to an immutable instance ?Sort of possible with a library solution: import std.typecons; auto x1 = rebindable(MyInfos.one);This rebindable is not user friendly. I really wish the user could write this Info x = MyInfos.one; I may achieve this if Info is defined as a struct with a single member defined as rebindable.Well, as long as you're dealing with local variables, you can use auto rather than typing the type explicitly, and then you don't need to explicitly use Rebindable, though you generally would for function parameters and member variables. But while typing Rebindable is a bit ugly, it's basically just a bit more verbose than what you'd get if it were built in. Right now you have Rebindable!Info info; whereas if it were buit in, you'd probably get something like tail_const(Info) info; or I think that someone suggested something like const(ref) Info info; And both of those are about as verbose as Rebindable is. So, they wouldn't save us much. So, sure, it would be nice if tail-const classes were built into the language, but we don't seem to be losing much by not having them. If someone could come up with why the lack of tail-const classes were a major roadblocker somehow, then maybe Walter could be convinced to alter the language, but you'd need a very solid reason as to why Rebindable doesn't cut it, and thinking that it's a bit ugly isn't going to be enough. - Jonathan M Davis
May 20 2016
Unfortunately it is not possible to write this import std.typecons; class Info{...} rebindable!Info x; I get the following error message source/app.d(11,3): Error: template std.typecons.rebindable matches more than one template declaration: /usr/include/dmd/phobos/std/typecons.d(1675,14): rebindable(T)(T obj) if (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArray!T) and /usr/include/dmd/phobos/std/typecons.d(1694,14): rebindable(T)(Rebindable!T obj) This would have been equivalent to define a mutable reference to an object of type Info and allow me to write this alias rebindable!Info InfoR; InfoR x; Unfortunately I didn't manage to get something compiling with rebindable. I don't understand how I'm supposed to use it. Note that I'm designing a library that I would like intuitive to use. Hacking around the problem won't cut it. I need a type defining a mutable reference to an immutable object. Rebindable doesn't give me that apparently. I need something allowing me to write this interface Info {...} class MyInfos { static class Obj : Info {...} static immutable Obj one = new immutable Obj(...); } mutableObjectRef!Info x1, x2; assert(x1 is null); assert(x1 == null); x1 = MyInfos.one; assert(x1 is MyInfos.one); assert(x1 == MyInfos.one); x2 = x1; switch(x1){ case MyInfos.one: ... ; default:...; } x1 must have the semantic of an object reference, support polymorphism, allowing to down or up cast and of course access immutable members and methods. MyInfos.one is an object reference that I shouldn't be allowed to modify. I can't use a function because it needs the value semantic so I can use it as a case argument in a switch. It doesn't seam that this is what rebind provides. It looks like mutableObjectRef should be a templated struct. But I'm not experienced enough in D to implement it. I don't know if its only possible.
May 21 2016
Since I'm trying to implement a flyweight pattern, the opEqual need only comparision of reference in my case. By the way, what operation is the switch performing ? OpEqual or is ?
May 21 2016
On 05/21/2016 01:07 AM, chmike wrote:Unfortunately it is not possible to write this import std.typecons; class Info{...} rebindable!Info x;You have a capitalization typo. Rebindable is a type template, rebindable is a function template. import std.typecons; class Info{} void main() { auto x = rebindable(new immutable(Info)()); pragma(msg, typeof(x)); auto y = Rebindable!(immutable(Info))(new Info()); pragma(msg, typeof(y)); } Ali
May 21 2016
On Saturday, 21 May 2016 at 08:24:19 UTC, Ali Çehreli wrote:On 05/21/2016 01:07 AM, chmike wrote:Thank you. I'll start a new thread with the subject "problems with Rebindable". See https://forum.dlang.org/post/bprfdptcvzzkfzxlhflb forum.dlang.orgUnfortunately it is not possible to write this import std.typecons; class Info{...} rebindable!Info x;You have a capitalization typo. Rebindable is a type template, rebindable is a function template. import std.typecons; class Info{} void main() { auto x = rebindable(new immutable(Info)()); pragma(msg, typeof(x)); auto y = Rebindable!(immutable(Info))(new Info()); pragma(msg, typeof(y)); } Ali
May 21 2016
On Friday, 20 May 2016 at 20:30:22 UTC, chmike wrote:I'm a bit surprized that the language doesn't support this. We have immutable strings that can be assigned to different variables. Why couldn't we do the same with objects ?Consider this: immutable(char)[] str; Here, the array elements of str are immutable, i.e. you cannot do this: str[0] = 's' However, the array reference itself is mutable, so you can freely assign array references around. This is what string is aliased to. To prevent the array reference from being assigned: immutable(char[]) str; Now trying to assign another string to str will produce a compiler error. With arrays and pointers, we distinguish between the data and the reference. With classes, we do not; there is only the reference.
May 20 2016
On Friday, 20 May 2016 at 16:09:54 UTC, chmike wrote:But I now met another error in my main(). I can't assign the immutable object to a mutable reference. Info x1 = MyInfos.one; Is it possible to define a mutable reference to an immutable instance ? This is confusing and frustrating. In C++ we can write MyInfos { . . . // one is a constant pointer to a constant object of type Obj Obj const * const one; . . . }I strongly advise you put C++ out of your head when programming D and try to come at it as if you have never seen C++. Otherwise, you will just keep getting frustrated. D is a different language and, while some C++ idioms may work just fine, others do not and cannot. Consider this: immutable(int*) ifoo; Because the * is inside the parens in the declaration of ifoo, we are saying that we never want the pointer to be reassigned. The compiler is free to behave as if that is true and that ifoo will always point to the same address. It might make certain optimizations based on that guarantee that might not otherwise be possible. The same is true if you replace immutable with const in this particular declaration. If you somehow manage to circumvent that guarantee, then you are breaking the compiler's expectations and entering the realm of undefined behavior. You can think of an immutable class reference as being an immutable pointer like ifoo. C++ has no such guarantees. The compiler is not free to make the same assumptions D can make. If D allowed you to do what C++ does, then D compilers would be in the same boat. This is one of the reasons why you can't expect D code to behave like C++ code in every case, no matter how similar things look on the surface.
May 20 2016
On Friday, 20 May 2016 at 16:09:54 UTC, chmike wrote:This is confusing and frustrating. In C++ we can write MyInfos { . . . // one is a constant pointer to a constant object of type Obj Obj const * const one; . . . } And in main() Info const * x1 = MyInfos.one; x1 i a modifiable pointer to a constant object of type Info. Is this possible in D ? I couldn't find how to do that.I should have addressed this above. This is another of the those things that will bite you if you are thinking in C++ when writing D. Classes in D are references types, so right out of the gate they can not be treated as C++ classes. You absolutely can have modifiable pointers to const and immutable data with built in types and structs, but not with classes. Always think of const(classref) as const(class*). There is no such thing as const(class)* in D.
May 20 2016