Possible way to achieve lazy loading with const objects

Simen Kjaeraas simen.kjaras at gmail.com
Mon Sep 26 07:43:56 PDT 2011


On Mon, 26 Sep 2011 02:18:30 +0200, Jonathan M Davis <jmdavisProg at gmx.com>  
wrote:

> On Monday, September 26, 2011 02:02:06 Simen Kjaeraas wrote:
>> On Sat, 24 Sep 2011 13:19:33 +0200, Peter Alexander
>>
>> <peter.alexander.au at gmail.com> wrote:
>> > Lazy loading and caching are the same thing.
>> >
>> > struct Foo
>> > {
>> >
>> >      T m_lazyObj = null;
>> >      bool m_isLoaded = false;
>> >
>> >      T getObj()
>> >      {
>> >
>> >          if (!m_isLoaded)
>> >          {
>> >
>> >              m_lazyObj = func();
>> >              m_isLoaded = true;
>> >
>> >          }
>> >          return m_lazyObj;
>> >
>> >      }
>> >
>> > }
>> >
>> > Change m_lazyObj to m_cachedObj and m_isLoaded to m_isCached and you
>> > have caching.
>>
>> This is too simple. If the system also rewrites all members to  
>> @properties
>> that
>> sets m_isLoaded = true, it might work. Example:
>>
>> struct S {
>>      int n;
>>      lazy int otherN = () { return n + 2; } // compile time error here  
>> if
>> you refer to lazily initialized members.
>> }
>
> Why would that be a compile time error? otherN won't be initialized until
> after n is. I suppose that it would be a problem if you tried to use  
> otherN in the constructor, but if that's the case, why lazily load it? We
> could simply disallow the use of lazy member variables in constructors -
> though then you'd have to worry about whether a lazy member variable were
> used in any functions which the constructor called, so you'd probably
> have to disallow calling other member functions inside of the  
> constructors
> of objects with lazy member variables. So, it does start to get a bit
> restrictive.

I might have been a bit unclear here. This is allowed:

struct S {
     int n;
     lazy int otherN = (){ return n + 2; };
}

This is not:

struct S2 {
     int n;
     lazy int otherN = (){ return n + 2; };
     lazy int otherOtherN = (){ return otherN + 2; }; // Error!
}

(I forgot to specify this) The initializing function needs to be pure and
depend only on non-logical const members (otherwise it may break the const
guarantee, by e.g. being dependent upon its own previous value).
Conceivably it could depend on other logconst members, but only if these
dependencies form no loops (which would logically be infinite).


>> Now, the overhead might be troublesome, but this seems to me to work.
>
> That doesn't scale, and the compiler would have to know that it need
> to do that to n because the function inilializing otherN used n.

That's why I said "rewrites all members". What really makes this untenable
is nested structs. Those would of course also have to be rewritten so that
changing one of their members would dirty the outer struct. It should come
as no surprise that this is unpossible.

An obvious optimization is, as you say, to only rewrite the members that
actually do influence the value of the logconst member.

-- 
   Simen


More information about the Digitalmars-d mailing list