On Monday, September 26, 2011 08:01:29 Steven Schveighoffer wrote: > On Sat, 24 Sep 2011 00:11:52 -0400, Jonathan M Davis <jmdavisp...@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. > > struct S > > { > > > > lazy T var = func(); > > > > } > > > > The lazy indicates that var is going to be lazily loaded, and func > > returns the > > value that var will be initialized with. However, instead of being a > > normal > > variable of type T, this is what happens to var: > > > > 1. Instead of a member variable of type T, S gets a bool (e.g. > > __varLoaded) > > and a variable of type T (e.g. __var). > > > > 2. __varLoaded is default-initialized to false, and __var is void (so, > > garbage). > > > > 3. Every reference to var is replaced with a call to a getter property > > function (e.g. __varProp). There is no setter property. > > > > 4. __varProp looks something like this: > > > > T __varProp() > > { > > > > if(!__varLoaded) > > { > > > > __var = func(); > > __varLoaded = true; > > > > } > > > > return __var; > > > > } > > > > 5. __varProp may or may not be inlined (but it would be nice if it > > would be). > > > > 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. > > So, the question is: Does this work? And if not, why? And if it _does_ > > work, > > is it a good idea? And if not, why? > > It doesn't solve the problem. Well, it was never intended to solve the _whole_ problem. It's an attempt at solving a piece of the problem. As far as I can see, enforcing logical constness with const is completely intractable, but lazy loading at least seems like it could be done, which would _partially_ solve the problem. Of course, the fact that it only partially solves the problem makes it far less valuable (and arguably not worth it given the extra complexity), but it does make it possible to solve _part_ of the problem instead of _none_ of the problem. - Jonathan M Davis