Possible way to achieve lazy loading with const objects

Steven Schveighoffer schveiguy at yahoo.com
Mon Sep 26 12:02:24 PDT 2011


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

> On Monday, September 26, 2011 10:26 Steven Schveighoffer wrote:
>> On Mon, 26 Sep 2011 12:12:30 -0400, Jonathan M Davis  
>> <jmdavisProg at gmx.com>
>>
>> wrote:
>> >
>> > 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.
>
> The problem with immutable is that it could (at least in theory) go in  
> read-
> only memory, so lazy initalization doesn't work for it _at all_.

That is not a good reason :)  Of course, any lazy initializers would have  
to be called during compilation time if the variable is put into ROM!  Any  
lazy initializer that doesn't run during CTFE would result in a compiler  
error.

>> 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.
>
> People have been complaining about the lack of logical const. The two use
> cases that they seem to have been looking for are the ability cache the
> results of member functions and to lazily load member variables. They  
> want to
> be able to do those things with const and can't (in the case of Peter
> Alexander, he seems to have come to the conclusion that it's bad enough  
> that
> he doesn't use const for anything not related to threaings, though I do  
> find
> that stance a bit odd, since it's _immutable_ that's needed for  
> threading, not
> const). I was merely trying to present a solution to lazy loading that  
> worked
> with const. It would therefore partially solve the issues that people  
> have
> been complaining about.

Forgive me for objecting, but a lazy-initialization scheme that eagerly  
initializes isn't even a valid solution.  I don't mean to be blunt, but I  
just can't put it any other way.

I see that you intended it to work lazily for non-const non-immutable  
items, but what would be the point then?  I can implement lazy  
initialization on mutable types today.

> Personally, I don't think that the feature merits the extra complexity  
> that it
> incurs. I was just proposing a possible solution. And it seems that some  
> folks
> (Peter in particular) don't think that it goes far enough to be of any  
> real
> value anyway (he wants full-on caching, not lazy loading). Personally, I  
> don't
> even remember the last time that I used lazy loading or caching in a  
> type, so
> the feature was never intended for me anyway, and finding out why folks  
> would
> find it useful would really require their input. But there _are_ people  
> who
> have wanted lazy loading to work with const objects; they just also want
> generally caching to work as well, which isn't at all feasible as far as  
> I can
> tell, whereas lazy loading seems like it could be.

I think a better avenue would be to implement some sort of strong-pure  
memoization system.  Then all you have to do is make an immutable pure  
member, and the compiler will take care of the rest for you.

I think this only works for classes, however, since there is no place to  
put hidden memoization members.

-Steve


More information about the Digitalmars-d mailing list