www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - const member function

reply "rumbu" <rumbu rumbu.ro> writes:
Often I'm using the following code pattern:

class S
{
    private SomeType cache;

    public SomeType SomeProp()  property
    {
       if (cache is null)
         cache = SomeExpensiveOperation();
       return cache;
    }
}

Is there any way to mark SomeProp() as const? Because I want to 
call somewhere const(S).SomeProp, which for the outside world is 
must be "const", returning just a value, even that internaly it 
modifies the internal S structure.
Feb 20 2015
next sibling parent reply "Baz" <bb.temp gmx.com> writes:
---
class S
{
     private SomeType cache;

     public const(SomeType) SomeProp()  property
     {
        if (cache is null)
          cache = SomeExpensiveOperation();
        return cache;
     }
}
---

the result of the getter will be read-only
Feb 20 2015
parent reply "rumbu" <rumbu rumbu.ro> writes:
On Saturday, 21 February 2015 at 07:01:12 UTC, Baz wrote:
 ---
 class S
 {
     private SomeType cache;

     public const(SomeType) SomeProp()  property
     {
        if (cache is null)
          cache = SomeExpensiveOperation();
        return cache;
     }
 }
 ---

 the result of the getter will be read-only
My intention is not to have a read-only getter, I want to call SomeProp on a const object: class S { private int cache = -1; private int SomeExpensiveOp() { return 12345; } public property const(int) SomeProp() { if (cache = -1) cache = SomeExpensiveOp(); return cache; } } unittest { const(S) s = new S(); auto i = s.SomeProp; //mutable method S.SomeProp is not callable using a const object }
Feb 20 2015
next sibling parent reply Mike Parker <aldacron gmail.com> writes:
On 2/21/2015 4:31 PM, rumbu wrote:

 My intention is not to have a read-only getter, I want to call SomeProp
 on a const object:

 class S
 {
      private int cache = -1;
      private int SomeExpensiveOp() { return 12345; }

      public  property const(int) SomeProp()
      {
          if (cache = -1)
              cache = SomeExpensiveOp();
          return cache;
      }
 }
const is transitive. If an instance of S is const, then all of its members are const, too. You cannot modify cache in that case. Assuming cache only needs to be initialized once, you can do this instead: this() { cache = SomeExpensiveOp(); } public property const(int) SomeProp() const { return cache; } Notice the const on the end of SomeProp. That makes the function callable on a const instance, but you still cannot modify cache inside of it.
Feb 21 2015
parent reply "rumbu" <rumbu rumbu.ro> writes:
On Saturday, 21 February 2015 at 08:08:25 UTC, Mike Parker wrote:
 On 2/21/2015 4:31 PM, rumbu wrote:

 you can do this instead:

     this() { cache = SomeExpensiveOp(); }

     public  property const(int) SomeProp() const
     {
         return cache;
     }

 Notice the const on the end of SomeProp. That makes the 
 function callable on a const instance, but you still cannot 
 modify cache inside of it.
My question was not how I do this, I know already. My question was if there is another way to safely call a non-const instance function on a const object. Initializing "cache" in the constructor will defeat the cache mechanism itself an that's I want to avoid.
Feb 21 2015
next sibling parent Jonathan M Davis via Digitalmars-d-learn writes:
On Saturday, February 21, 2015 08:27:13 rumbu via Digitalmars-d-learn wrote:
 On Saturday, 21 February 2015 at 08:08:25 UTC, Mike Parker wrote:
 On 2/21/2015 4:31 PM, rumbu wrote:

 you can do this instead:

     this() { cache = SomeExpensiveOp(); }

     public  property const(int) SomeProp() const
     {
         return cache;
     }

 Notice the const on the end of SomeProp. That makes the
 function callable on a const instance, but you still cannot
 modify cache inside of it.
My question was not how I do this, I know already. My question was if there is another way to safely call a non-const instance function on a const object. Initializing "cache" in the constructor will defeat the cache mechanism itself an that's I want to avoid.
Nope. If you want to use caching, you can't do it with const. D's const is transitive, and it's not logical const. It's physical const. If _any_ portion of an object were to be mutated by a const function, it would violate the type system. Unlike C++'s const, D's const provides actual guarantees about the data not changing, which can be useful for some optimizations but is outright required because of immutable. For instance, imagine if your object were immutable and your const function were somehow able to mutate on of the object's members (e.g. by casting away const). An immutable object could be in read-only-memory, in which case, that would segfault. And even if it didn't, it could cause really weird bugs due to the fact that the compiler is free to assume that an immutable object never changes and that an object can never be mutated via a const reference. The fact that immutable objects are implicitly shared would make it even worse, because then you'd risk thread-related issues to boot. The reality of the matter is that if you want to do any kind of caching like this, you either have to do the caching only in mutable functions (in which case, the const function could take advantage of the cached value if it were there but would have to calculate it if it hadn't been cached already), or you can't do caching at all. Ultimately, for better or worse, D's const is a very different beast from C++'s const, and you can't approach them the same way. This SO question discusses the issue: http://stackoverflow.com/questions/4219600/logical-const-in-d - Jonathan M Davis
Feb 21 2015
prev sibling parent reply ketmar <ketmar ketmar.no-ip.org> writes:
On Sat, 21 Feb 2015 08:27:13 +0000, rumbu wrote:

 My question was not how I do this, I know already. My question was if
 there is another way to safely call a non-const instance function on a
 const object.
is there a way to been safely hit by a truck?=
Feb 21 2015
next sibling parent "Foo" <Foo test.de> writes:
On Saturday, 21 February 2015 at 15:26:28 UTC, ketmar wrote:
 On Sat, 21 Feb 2015 08:27:13 +0000, rumbu wrote:

 My question was not how I do this, I know already. My question 
 was if
 there is another way to safely call a non-const instance 
 function on a
 const object.
is there a way to been safely hit by a truck?
In a tank. ;)
Feb 21 2015
prev sibling parent reply "rumbu" <rumbu rumbu.ro> writes:
On Saturday, 21 February 2015 at 15:26:28 UTC, ketmar wrote:
 On Sat, 21 Feb 2015 08:27:13 +0000, rumbu wrote:

 My question was not how I do this, I know already. My question 
 was if
 there is another way to safely call a non-const instance 
 function on a
 const object.
is there a way to been safely hit by a truck?
I thought if there is some language construct similar to trusted for safe, applicable to const member functions. You can be safely hit by a truck if I tell you that there is no truck around :)
Feb 23 2015
next sibling parent ketmar <ketmar ketmar.no-ip.org> writes:
On Mon, 23 Feb 2015 09:12:33 +0000, rumbu wrote:

 On Saturday, 21 February 2015 at 15:26:28 UTC, ketmar wrote:
 On Sat, 21 Feb 2015 08:27:13 +0000, rumbu wrote:

 My question was not how I do this, I know already. My question was if
 there is another way to safely call a non-const instance function on a
 const object.
is there a way to been safely hit by a truck?
=20 I thought if there is some language construct similar to trusted for safe, applicable to const member functions. You can be safely hit by a truck if I tell you that there is no truck around :)
do not make it `const` at all. i see something very strange in making=20 something `const` just to find the way to remove constness. just stop=20 writing C++ code in D.=
Feb 23 2015
prev sibling parent Jonathan M Davis via Digitalmars-d-learn writes:
On Monday, February 23, 2015 09:12:33 rumbu via Digitalmars-d-learn wrote:
 On Saturday, 21 February 2015 at 15:26:28 UTC, ketmar wrote:
 On Sat, 21 Feb 2015 08:27:13 +0000, rumbu wrote:

 My question was not how I do this, I know already. My question
 was if
 there is another way to safely call a non-const instance
 function on a
 const object.
is there a way to been safely hit by a truck?
I thought if there is some language construct similar to trusted for safe, applicable to const member functions. You can be safely hit by a truck if I tell you that there is no truck around :)
No. That wouldn't work at all because of immutable. A const method can be called on an immutable variable just as well as it can be called on a const or mutable one. In addition to that, Walter Bright feels very strongly that const should provide actual compiler guarantees, and when you have something like C++'s mutable which gives you a backdoor on const, the compiler can't really guarantee much of anything. trusted has similar problems in that the programmer can screw it up and mark stuff as trusted which makes the calling code unsafe, but that would be an actual bug in the program, whereas C++s mutable isn't a bug. Mutating const is perfectly acceptle in C++. It just doesn't work unless you tell the compiler to let you do it anyway, and the behavior is well-defined, whereas doing anything like casting away const and mutating a variable in D is undefined behavior, because the compiler is free to rely on const variables not changing so long as it can guarantee that a mutable reference to the same data can't have mutated that data. And yes, on some level, that sucks, because stuff like caching doesn't work with const, but it does mean that you can rely on const actually being const, which does provide other benefits. It does take some getting used to though. Regardless, the fact that we have immutable pretty much forces the issue - especially when you consider that the compiler can choose to put immutable variables in read-only-memory if it thinks that makes sense. - Jonathan M Davis
Feb 23 2015
prev sibling parent "Baz" <bb.temp gmx.com> writes:
On Saturday, 21 February 2015 at 07:31:19 UTC, rumbu wrote:
 On Saturday, 21 February 2015 at 07:01:12 UTC, Baz wrote:
 ---
 class S
 {
    private SomeType cache;

    public const(SomeType) SomeProp()  property
    {
       if (cache is null)
         cache = SomeExpensiveOperation();
       return cache;
    }
 }
 ---

 the result of the getter will be read-only
My intention is not to have a read-only getter, I want to call SomeProp on a const object: class S { private int cache = -1; private int SomeExpensiveOp() { return 12345; } public property const(int) SomeProp() { if (cache = -1) cache = SomeExpensiveOp(); return cache; } } unittest { const(S) s = new S(); auto i = s.SomeProp; //mutable method S.SomeProp is not callable using a const object }
right, i have not carefully read the body of the Q. my bad.
Feb 21 2015
prev sibling parent "Foo" <Foo test.de> writes:
On Saturday, 21 February 2015 at 06:38:18 UTC, rumbu wrote:
 Often I'm using the following code pattern:

 class S
 {
    private SomeType cache;

    public SomeType SomeProp()  property
    {
       if (cache is null)
         cache = SomeExpensiveOperation();
       return cache;
    }
 }

 Is there any way to mark SomeProp() as const? Because I want to 
 call somewhere const(S).SomeProp, which for the outside world 
 is must be "const", returning just a value, even that internaly 
 it modifies the internal S structure.
AFAIK it is unsafe and not recommended, but this works for me: ---- import std.stdio; class Foo { void say(string s) const { writeln(s); } } class Bar { Foo f; const(Foo) getFoo() const { if (!f) cast() this.f = new Foo(); return f; } } void main() { Bar b = new Bar(); const Foo f = b.getFoo(); f.say("Hello"); } ----
Feb 21 2015