www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - "Semi-const" methods?

reply Magnus Lie Hetland <magnus hetland.org> writes:
I have a data structure that's generally static (const, or even 
immutable), but it has some utility storage, which caches certain 
results during use. This caching etc. doesn't really affect the 
semantics of the main object, and are reset between operations, so I 
think it still would be useful to declare (and statically check) that 
certain methods don't modify any of the *rest* of the structure (i.e., 
the "main parts").

I *could* declare the methods const, and pass in a second object (a 
non-const parameter) for the caching etc. Or I cast the relevant parts 
to const (assigning them to local variables) early on in the relevant 
methods (dropping the const modifier on the method itself -- sort of a 
bummer).

Any other ideas on how to handle this sort of "mostly const" or "const 
where it counts" stuff? Perhaps my design intentions here are off to 
begin with?-)

-- 
Magnus Lie Hetland
http://hetland.org
Mar 13 2011
next sibling parent reply Magnus Lie Hetland <magnus hetland.org> writes:
On 2011-03-13 23:27:14 +0100, Magnus Lie Hetland said:

 Any other ideas on how to handle this sort of "mostly const" or "const 
 where it counts" stuff? Perhaps my design intentions here are off to 
 begin with?-)

OK -- a *little* quick on the trigger there. My solution: Declare the method const, and assign the non-essential cache stuff to local variables, casting away the constness. (Still open to schooling on the design part of this, though. Perhaps declaring a method as const is no good when it's not *really* const? For now, I'm just doing it to check that I don't inadvertently change things I don't want to change.) -- Magnus Lie Hetland http://hetland.org
Mar 13 2011
next sibling parent Magnus Lie Hetland <magnus hetland.org> writes:
On 2011-03-13 23:32:34 +0100, Magnus Lie Hetland said:

 (Still open to schooling on the design part of this, though. Perhaps 
 declaring a method as const is no good when it's not *really* const? 
 For now, I'm just doing it to check that I don't inadvertently change 
 things I don't want to change.)

Actually, I have a local (recursive) traversal function in the method I was talking about. Ended up not declaring the method as const, but declaring the argument of the traversal function as const. No misleading const declarations "outside", and I get the automatic checks that I want. -- Magnus Lie Hetland http://hetland.org
Mar 13 2011
prev sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday 13 March 2011 15:32:34 Magnus Lie Hetland wrote:
 On 2011-03-13 23:27:14 +0100, Magnus Lie Hetland said:
 Any other ideas on how to handle this sort of "mostly const" or "const
 where it counts" stuff? Perhaps my design intentions here are off to
 begin with?-)

OK -- a *little* quick on the trigger there. My solution: Declare the method const, and assign the non-essential cache stuff to local variables, casting away the constness. (Still open to schooling on the design part of this, though. Perhaps declaring a method as const is no good when it's not *really* const? For now, I'm just doing it to check that I don't inadvertently change things I don't want to change.)

What you want is logical const. You want it to be const from the perspective of an observer of the function but actually have stuff non-const within it. C++ has the mutable keyword to handle this. It's also completely legal and well-defined to cast away constness in C++. D, on the other hand, does not technically support logical const at all. It has to do with the complete lack of compiler guaranteeds. You _can_ cast away constness in D, but it's breaking the type system when you do. It is perfectly valid for the compiler to assume that you function really is const and optimize appropriately. So, if you don't actually manage to _really_ be logically const, or if you do this with an immutable object (which would likely result in a segfault), you _are_ going to have incorrect code. On the whole, I'd advise just not using const when you need logical const, but if you're _very_ careful, you can get away with it. But thanks to immutable, it can be _very_ dangerous to cast away constness in a const function unless you're _very_ careful. You really should check out this question on stackoverflow and the answers that go with it: http://stackoverflow.com/questions/4219600/logical-const-in-d - Jonathan M Davis
Mar 13 2011
parent Magnus Lie Hetland <magnus hetland.org> writes:
On 2011-03-14 00:17:18 +0100, Jonathan M Davis said:

 So, if you don't actually manage to _really_
 be logically const, or if you do this with an immutable object (which would
 likely result in a segfault), you _are_ going to have incorrect code. On the
 whole, I'd advise just not using const when you need logical const, but if
 you're _very_ careful, you can get away with it. But thanks to 
 immutable, it can
 be _very_ dangerous to cast away constness in a const function unless you're
 _very_ careful.
 
 You really should check out this question on stackoverflow and the answers that
 go with it: http://stackoverflow.com/questions/4219600/logical-const-in-d

Thanks for the insights + tip :) -- Magnus Lie Hetland http://hetland.org
Mar 14 2011
prev sibling parent reply Mafi <mafi example.org> writes:
Am 13.03.2011 23:27, schrieb Magnus Lie Hetland:
 I have a data structure that's generally static (const, or even
 immutable), but it has some utility storage, which caches certain
 results during use. This caching etc. doesn't really affect the
 semantics of the main object, and are reset between operations, so I
 think it still would be useful to declare (and statically check) that
 certain methods don't modify any of the *rest* of the structure (i.e.,
 the "main parts").

 I *could* declare the methods const, and pass in a second object (a
 non-const parameter) for the caching etc. Or I cast the relevant parts
 to const (assigning them to local variables) early on in the relevant
 methods (dropping the const modifier on the method itself -- sort of a
 bummer).

 Any other ideas on how to handle this sort of "mostly const" or "const
 where it counts" stuff? Perhaps my design intentions here are off to
 begin with?-)

I found away which doesn't use casts or bugs. Just use delegates/closures. class C { int i; int delegate(int) getCache; this(int fi) { this.i = fi; int lastX, lastR; this.getCache = (int x) { if(x == lastX) return lastR; lastX = x; lastR = x * i; return lastR; }; } const multiply(int x) { return getCache(x); } }
Mar 14 2011
parent Magnus Lie Hetland <magnus hetland.org> writes:
On 2011-03-14 11:51:09 +0100, Mafi said:

 I found away which doesn't use casts or bugs.
 Just use delegates/closures.

Nice :D -- Magnus Lie Hetland http://hetland.org
Mar 14 2011