Thread overview | |||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
May 20, 2016 Immutable objects and constructor ? | ||||
---|---|---|---|---|
| ||||
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 Re: Immutable objects and constructor ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to chmike | 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 Re: Immutable objects and constructor ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Kagamin | On Friday, 20 May 2016 at 14:40:23 UTC, Kagamin wrote:
> 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.
Thank you very much for the fast and very helpful reply. I'll try that.
|
May 20, 2016 Re: Immutable objects and constructor ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to chmike | 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 Re: Immutable objects and constructor ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to chmike | 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 Re: Immutable objects and constructor ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to chmike | 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 Re: Immutable objects and constructor ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marc Schütz | 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 Re: Immutable objects and constructor ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to chmike | 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 Re: Immutable objects and constructor ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Kagamin | On Friday, 20 May 2016 at 17:35:01 UTC, Kagamin wrote:
> 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);
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.
|
May 20, 2016 Re: Immutable objects and constructor ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to chmike | 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: > > 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); > > 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 ? 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. > 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 |
Copyright © 1999-2021 by the D Language Foundation