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