Possible way to achieve lazy loading with const objects

Steven Schveighoffer schveiguy at yahoo.com
Thu Sep 29 06:24:03 PDT 2011


On Thu, 29 Sep 2011 04:12:01 -0400, Peter Alexander  
<peter.alexander.au at gmail.com> wrote:

> On 29/09/11 8:13 AM, Marco Leise wrote:
>> Am 26.09.2011, 18:12 Uhr, schrieb Jonathan M Davis  
>> <jmdavisProg at gmx.com>:
>>
>>> On Monday, September 26, 2011 08:01:29 Steven Schveighoffer wrote:
>>>> For example, storing a reference to a mutex in an object, or a  
>>>> reference
>>>> to an owner object. It's the difference between a "has a" relationship
>>>> and a "points to" relationship.
>>>>
>>>> Your lazy loading idea does not help at all for these.
>>>
>>> I believe that the two main complaints about the lack of logical const
>>> which
>>> have been coming up in the newsgroup have been the inability to cache  
>>> the
>>> return values of member functions and the inability to lazily load the
>>> values of member variables.
>>
>> I brought the issue with "points to" relationships up in another thread
>> here - also about transitive const. I believe a proper object-oriented
>> design should allow for pointers to other objects that have nothing in
>> common with the host object. car.getVendor() for example should always
>> return the mutable instance of the shop where that - possibly const car
>> - was bought. Let's call it the "parent reference" issue for short :)
>> +1 to Steven's comment.
>
> Why would a car be able mutate it's vendor?

Because a vendor is not part of a car.  It's a link.

In logical const land, the point of the piece of logical const data is  
that it's not part of the object's state.  It's a piece of data *related*  
to the object, but not *part* of the object.

My favorite example is a Widget and a window to draw the widget in.  The  
primitives for drawing in the window obviously cannot be const, because  
they alter the window.  However, it makes complete sense that when drawing  
an object, you don't want it's state to change.  So how to define the  
widget?

Window w;
const draw();

This doesn't work, because the window is a part of the widget state, and  
therefore const.  So you can't draw anything in the window inside the draw  
function.

There are two possible solutions.  First is, just make it not const.  But  
then you lose any guarantees that the compiler gives you about not having  
the object state change.  Second option is to pass the window into the  
widget:

const draw(Window w);

But then, it becomes cumbersome to drag around a window reference  
everywhere you have a Widget reference.

What logical const does is allocate space that is *associated* with the  
object, but not *owned* by the object.  It actually doesn't matter if it  
lives in the object's block or not.

> Also, the problem with mutable parent references is that it completely  
> defeats the purpose of const. Consider this C++ code:
>
> struct Tree
> {
>      Tree* m_parent;
>      std::vector<Tree> m_children;
>
>      void doSomethingConst() const;
> };
>
> The tree owns it's children, and has a mutable reference back to its  
> parent.
>
> Inside doSomethingConst, I shouldn't be able to modify my children  
> because I own them, however, you are arguing that I should be able to  
> get a mutable reference to my parent. However, if I can get a mutable  
> reference to my parent, then I can get mutable references to its  
> children, of which (this) is one. So, through my parent I can get a  
> mutable reference to myself, circumventing the const, making it  
> pointless.

This is a tricky situation.  I think logical const only makes sense if  
there are no cycles.  That is, in my widget example, the window doesn't  
know about the widget, and does not have a pointer back to it.

I think in your example, the parent should be part of the tree state,  
since it contains itself.  Therefore, logical const should not be used.

Such a thing is impossible to prove by the compiler, so logical const does  
break the compiler guarantees.  There is no way to allow logical const in  
the case of the widget, and not allow it in the case of the Tree struct.

>
> Strict transitive const is essential. Without it, it becomes far too  
> easily to wriggle your way out of const, which breaks the guarantees of  
> immutable.

This is not true.  An immutable object is never mutable, and could never  
be assigned to a mutable reference, even if that reference was inside a  
logically const object.

Logical const only comes into play when you are talking about mutable  
pieces that are temporarily cast to const.

-Steve


More information about the Digitalmars-d mailing list