www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Lazily evaluated property pointing to read only object

reply mikey <abc.mikey googlemail.com> writes:
I'm trying to figure out how to best write a class with a 
property that is only evaluated when it's called for the first 
time. And that returns an object which shouldn't be modifiable a 
part of the owning class.

I've had a go at doing something like this but am not very sure 
if this is how to go about it.


     class Obj {
         string _s;

         this() {
             this("");
         }

         this(string s) {
             _s = s;
         }

          property string desc() const { return _s; }
          property void desc(string s) { _s = s; }

         override string toString() const {
             return _s;
         }
     }

     class ConstProp {
         Obj _o;
         string _s;

         this(string s) {
             _s = s;
         }

         const(Obj) lazily() {
             if (_o is null) {
                 _o = new Obj("working " ~ _s);
             }
             return cast(const(Obj)) _o;
         }
     }

     void main() {
         auto c = new ConstProp("test");
         writeln(c.lazily);
         writeln(c.lazily.desc);
     }
Sep 24 2016
parent reply Basile B. <b2.temp gmx.com> writes:
On Saturday, 24 September 2016 at 09:08:52 UTC, mikey wrote:
 I'm trying to figure out how to best write a class with a 
 property that is only evaluated when it's called for the first 
 time. And that returns an object which shouldn't be modifiable 
 a part of the owning class.

 I've had a go at doing something like this but am not very sure 
 if this is how to go about it.
 [...]


         const(Obj) lazily() {
             if (_o is null) {
                 _o = new Obj("working " ~ _s);
             }
             return cast(const(Obj)) _o;
         }
     }
You don't need to cast, from "mutable" to "const" is implicit: https://dlang.org/spec/const3.html#implicit_conversions
Sep 24 2016
parent reply mikey <abc.mikey googlemail.com> writes:
On Saturday, 24 September 2016 at 10:16:34 UTC, Basile B. wrote:
 You don't need to cast, from "mutable" to "const" is implicit:
 https://dlang.org/spec/const3.html#implicit_conversions
Ok, but using const would be an accepted way of doing this? The options I could see were to have "_o" as a const or immutable type and just create a const on the first call to the lazily evaluated property, or to do what I did and have "_o" as a non-const and then convert it to cost on the way out. However To store it as const I guess I'd have to make it a non-const pointer to a const object, and is that not kind of what immutable is?
Sep 24 2016
parent reply Basile B. <b2.temp gmx.com> writes:
On Saturday, 24 September 2016 at 10:59:50 UTC, mikey wrote:
 On Saturday, 24 September 2016 at 10:16:34 UTC, Basile B. wrote:
 You don't need to cast, from "mutable" to "const" is implicit:
 https://dlang.org/spec/const3.html#implicit_conversions
Ok, but using const would be an accepted way of doing this? The options I could see were to have "_o" as a const or immutable type and just create a const on the first call to the lazily evaluated property, or to do what I did and have "_o" as a non-const and then convert it to cost on the way out. However To store it as const I guess I'd have to make it a non-const pointer to a const object, and is that not kind of what immutable is?
Yes, the problem is that if you want to create a true const(Object) (with const part of the type) you have to initialize it in a constructor (so no lazyness). It indeed looks like the immutable mechanism. I don't know **exactly** why but I guess that's a special case for classes since there's no other way to initialize them. Finally, with the property your object is seen as const(Object) outside. The only difference is inside ConstProp.
Sep 24 2016
parent vit <vit vit.vit> writes:
On Saturday, 24 September 2016 at 11:51:56 UTC, Basile B. wrote:
 On Saturday, 24 September 2016 at 10:59:50 UTC, mikey wrote:
 On Saturday, 24 September 2016 at 10:16:34 UTC, Basile B. 
 wrote:
 You don't need to cast, from "mutable" to "const" is implicit:
 https://dlang.org/spec/const3.html#implicit_conversions
Ok, but using const would be an accepted way of doing this? The options I could see were to have "_o" as a const or immutable type and just create a const on the first call to the lazily evaluated property, or to do what I did and have "_o" as a non-const and then convert it to cost on the way out. However To store it as const I guess I'd have to make it a non-const pointer to a const object, and is that not kind of what immutable is?
Yes, the problem is that if you want to create a true const(Object) (with const part of the type) you have to initialize it in a constructor (so no lazyness). It indeed looks like the immutable mechanism. I don't know **exactly** why but I guess that's a special case for classes since there's no other way to initialize them. Finally, with the property your object is seen as const(Object) outside. The only difference is inside ConstProp.
use Rebindable: class Obj { string _s; this()pure{ this(""); } this(string s)pure{ _s = s; } property string desc() const { return _s; } property void desc(string s) { _s = s; } override string toString() const { return _s; } } class ConstProp { import std.typecons : Rebindable; Rebindable!(immutable Obj) _o; string _s; this(string s) { _s = s; } immutable(Obj) lazily(){ if (_o is null) { _o = new Obj("working " ~ _s); } return _o; } }
Sep 27 2016