Possible way to achieve lazy loading with const objects

Steven Schveighoffer schveiguy at yahoo.com
Mon Sep 26 10:26:41 PDT 2011


On Mon, 26 Sep 2011 12:12:30 -0400, Jonathan M Davis <jmdavisProg at gmx.com>  
wrote:

> On Monday, September 26, 2011 08:01:29 Steven Schveighoffer wrote:
>> On Sat, 24 Sep 2011 00:11:52 -0400, Jonathan M Davis  
>> <jmdavisProg at gmx.com>
>>
>> wrote:
>> > Okay. I'm not saying that we should necessarily implement this. I'm  
>> just
>> > looking to air out an idea here and see if there are any technical
>> > reasons why
>> > it can't be done or is unreasonable.
>> >
>> > Some programmers have expressed annoyance and/or disappointment that
>> > there is
>> > no logical const of any kind in D. They generally seem to be trying to
>> > do one
>> > of two things - caching return values in member functions or lazily
>> > loading
>> > the values of member variables.
>>
>> The major reason for having logical const is to a) store state on the
>> object that is not considered part of the object, or b) store references
>> to objects that are not part of the object state.
>>
>> 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. This is simply an attempt to solve the lazy loading
> portion of that problem.

Of course.  My point was that your two use cases I think are far less used  
than the refer-to-other-object-but-don't-own-it cases.

Maybe I'm wrong, it's been a long time since I used C++, and mutable in  
general.  But I remember using it when I wanted to have a reference to  
something that was not part of the object.

>> > 6.  If the S being constructed is shared or immutable and __varProp is
>> > not
>> > called in the constructor, then __varProp is called immediately after
>> > the
>> > constructor (or at the end of the constructor if that works better for
>> > the
>> > compiler).
>>
>> Why?  What if the calculation is very expensive, and you never access  
>> var?
>>
>> Besides, we can already pro-actively initialize data in an immutable
>> constructor, what is the benefit here?
>
> The point is that if aren't using immutable or shared, then you can  
> afford to
> lazy load it, so you can wait to initialize the variable until it's  
> used, but
> you _can't_ afford to do that in the case of immutable, because the data  
> must
> be immutable and can't be changed later to do the lazy loading, and you  
> can't
> afford to do that in the case of shared, because then you have  
> thread-safety
> issues, so you have to pay the cost upfront in those cases.

It is only important that the value is constant *when it's read*, not at  
the beginning of the object existence.  If you hook the only way to read  
it with a lazy initializer, then the two cases are indistinguishable, or  
using lazy initialization doesn't make sense.

Let's think of the case where *two* threads are lazily initializing an  
immutable struct.  None of the members can be any different, because they  
are immutable, so if the value depends solely on the internal struct data,  
then both initializers will set the *Same value*.  Two competing threads  
writing the same value do not result in corruption.

If the initializer depends on some *external state*, if that external  
state is also immutable, same result.

If the initializer depends on some external state that is *not* immutable,  
then why mark it lazy initialization?  What is the point of initializing  
data that depends on something that's changing over time?  I can't see the  
point of doing that.  This is of course, only if you can't restart the  
initialization (i.e. clear the 'set' flag).

Note that if you want your proposed behavior you can achieve it by  
defining a constructor that eagerly initializes the variable by simply  
reading it.

I still don't think this proposal (even one that always lazily  
initializes) gives enough benefit to be included.  Why would you want a  
constant lazily-initialized value in a non-immutable struct?  If this were  
to mean anything, there would have to be a way to clear the 'set' flag in  
a mutable struct.

-Steve


More information about the Digitalmars-d mailing list