View mode: basic / threaded / horizontal-split · Log in · Help
June 27, 2007
Lazy evaluation
Hey. I've been writing a bit on a "true" lazy evaluation (i.e. not evaluated until value is requested, but only evaluated once). A simple example of this can be achieved using a delegate, like so:

template Lazy(T)
{
	class Lazy
	{
		this(T delegate() exp)
		{
			mExp = exp;
		}

		T opCall()
		{
			if (!mEvaluated)
			{
				mValue = mExp();
				mEvaluated = true;
			}
			return mValue;
		}

	private:
		bool mEvaluated = false;
		final T delegate() mExp;
		T mValue;

	}
}

Which would work fine with Lazy!(int)( { return someExpr; } ), but it would be nice to be able to just use Lazy!(int)( someExpr ). However, it seems this can only be achieved using lazy function arguments, but problem is, if I use lazy function arguments, I can't really save it for later and do anything worthwhile with it.

Consider the additional constructor

this(lazy T lazyexp)
{
	mExp = { return lazyexp; };
}

which looks fine, but isn't (it crashed with Access Violation). It hints at lazyexp not being valid after the function has ended, which makes it quite different from delegates. Yet the article about lazy evaluation ( http://www.digitalmars.com/d/1.0/lazy-evaluation.html ) seems to indicate lazy is just syntetic sugar for delegates... but the behaviour is not like it at all. It doesn't seem to be able to convert a lazy expression to an delegate in any way (cast complains, the above, as said, crashes). Is there any way I've missed?

In addition, the above mentioned article states "So D takes it one small, but crucial, step further (suggested by Andrei Alexandrescu). Any expression can be implicitly converted to a delegate that returns either void or the type of the expression." which doesn't seem to be true either, or it would be enough with the first constructor that just uses the normal delegate syntax. Had this worked, it would have been fine for this case.

An other alternative I thought of was to save the lazy expression in the Lazy object instead of the delegate, but lazy seems to be completely restricted to function arguments. Is there any specific reason for this? I mean, "lazy int i = j++;" in, for example, a function isn't that much weirder. It's still just seems to be syntetic sugar for delegates, it should be able to work consistently with the behaviour of lazy for function arguments, should it not?

Any explanations or suggestions are welcome.

Slightly unrelated, is there anything in D corresponding to C++'s implicit cast operators (operator 'typename'(), e.g. operator int()) in D? I can't seem to find any...
June 27, 2007
Re: Lazy evaluation
OF wrote:
> It hints at lazyexp not being valid after the function has ended, which makes it quite different from delegates.

This is the /exact/ behavior of delegate liters and delegates formed 
from nested functions. They are invalid after the function call they are 
from returns. This is because the delegate caries a pointer to the stack 
frame of the surrounding function.
June 27, 2007
Re: Lazy evaluation
"OF" <nospam@nospammington.com> wrote in message 
news:f5u09a$1mmq$1@digitalmars.com...
>
> Slightly unrelated, is there anything in D corresponding to C++'s implicit 
> cast operators (operator 'typename'(), e.g. operator int()) in D? I can't 
> seem to find any...

Nope.  D doesn't have implicit casting as in C++.
June 27, 2007
Re: Lazy evaluation
BCS wrote:
> OF wrote:
>> It hints at lazyexp not being valid after the function has ended, 
>> which makes it quite different from delegates.
> 
> This is the /exact/ behavior of delegate liters and delegates formed 
> from nested functions. They are invalid after the function call they are 
> from returns. This is because the delegate caries a pointer to the stack 
> frame of the surrounding function.

Yeah, but only when you access some variables through this pointer right?
June 27, 2007
Re: Lazy evaluation
Lutger wrote:
> BCS wrote:
> 
>> OF wrote:
>>
>>> It hints at lazyexp not being valid after the function has ended, 
>>> which makes it quite different from delegates.
>>
>>
>> This is the /exact/ behavior of delegate liters and delegates formed 
>> from nested functions. They are invalid after the function call they 
>> are from returns. This is because the delegate caries a pointer to the 
>> stack frame of the surrounding function.
> 
> 
> Yeah, but only when you access some variables through this pointer right?

I would assume so but there might be some hidden reads that could cause 
problems.
June 27, 2007
Re: Lazy evaluation
BCS wrote:
> Lutger wrote:
>> BCS wrote:
>>
>>> OF wrote:
>>>
>>>> It hints at lazyexp not being valid after the function has ended, 
>>>> which makes it quite different from delegates.
>>>
>>>
>>> This is the /exact/ behavior of delegate liters and delegates formed 
>>> from nested functions. They are invalid after the function call they 
>>> are from returns. This is because the delegate caries a pointer to 
>>> the stack frame of the surrounding function.
>>
>>
>> Yeah, but only when you access some variables through this pointer right?
> 
> I would assume so but there might be some hidden reads that could cause 
> problems.

Could you elaborate? I see nothing in the spec that says it's legal or 
not. If there are problems with this, I think that should be clearly 
stated.
June 27, 2007
Re: Lazy evaluation
Lutger wrote:
> BCS wrote:
> 
>> Lutger wrote:
>>
>>> BCS wrote:
>>>
>>>> OF wrote:
>>>>
>>>>> It hints at lazyexp not being valid after the function has ended, 
>>>>> which makes it quite different from delegates.
>>>>
>>>>
>>>>
>>>> This is the /exact/ behavior of delegate liters and delegates formed 
>>>> from nested functions. They are invalid after the function call they 
>>>> are from returns. This is because the delegate caries a pointer to 
>>>> the stack frame of the surrounding function.
>>>
>>>
>>>
>>> Yeah, but only when you access some variables through this pointer 
>>> right?
>>
>>
>> I would assume so but there might be some hidden reads that could 
>> cause problems.
> 
> 
> Could you elaborate? I see nothing in the spec that says it's legal or 
> not. If there are problems with this, I think that should be clearly 
> stated.

I known of no cases where hidden read/writes happen, but unless the spec 
says so, I would not assume they don't happen if I could avoid it. The 
spec does say that a delegate to a nested function is invalid after the 
function returns (note nothing about if it access anything).

<start rant>

This is one reason where I would really like to see explicit contexts 
for delegate literals

class C{
	int i;
	int j;
}

void main(){
	C c = new C;
	void delegate (int, int) set = c.(int k, int l){
			i=k;
			j=l; // access any public parts of the thing
			};

		// delegate literal without risk of stack corruption
	void delegate() action = null.{someGlobalAction();};

	int i = 5;
	bool delegate(int) test = i.(int j){
			return this == j; // why not int for context?
			};		// sizeof(int) == sizeof(void*)

		// now how about 32bit structs by value?
	struct foo
	{
		short a;
		char b;
		byte c;
	}
	static assert(sizeof(foo) == sizeof(void*));

	foo dat = foo(45, 'c', 222)
	int delegate() go_v = dat.{return  a+b+c;};

		// now by reference
	int delegate() go_p = (&dat).{return  a+b+c;};

	dat.a = 0;
	dat.b = '\0';
	dat.c = 0;
	assert(go_v != 0);
	assert(go_p == 0);
}
June 28, 2007
Re: Lazy evaluation
Jarrett Billingsley wrote:
> "OF" <nospam@nospammington.com> wrote in message 
> news:f5u09a$1mmq$1@digitalmars.com...
>> Slightly unrelated, is there anything in D corresponding to C++'s implicit 
>> cast operators (operator 'typename'(), e.g. operator int()) in D? I can't 
>> seem to find any...
> 
> Nope.  D doesn't have implicit casting as in C++. 

...yet.

Dave
June 28, 2007
Re: Lazy evaluation
I really hope it doesn't... there are a _few_ times where it'd be nice for two classes to be inter-operable (mostly for backwards-compatibility purposes), but the majority of the time (like most operator overloads to me...) it's just confusing.

David B. Held Wrote:

> Jarrett Billingsley wrote:
> > "OF" <nospam@nospammington.com> wrote in message 
> > news:f5u09a$1mmq$1@digitalmars.com...
> >> Slightly unrelated, is there anything in D corresponding to C++'s implicit 
> >> cast operators (operator 'typename'(), e.g. operator int()) in D? I can't 
> >> seem to find any...
> > 
> > Nope.  D doesn't have implicit casting as in C++. 
> 
> ...yet.
> 
> Dave
June 28, 2007
Re: Lazy evaluation
Lutger Wrote:
> BCS wrote:
> > OF wrote:
> >> It hints at lazyexp not being valid after the function has ended, 
> >> which makes it quite different from delegates.
> > 
> > This is the /exact/ behavior of delegate liters and delegates formed 
> > from nested functions. They are invalid after the function call they are 
> > from returns. This is because the delegate caries a pointer to the stack 
> > frame of the surrounding function.
> 
> Yeah, but only when you access some variables through this pointer right?

If you don't need to do that then you want a function as opposed to a delegate, right?  Is such a thing possible in D, function literals.  You might need to explicitly say 'function' in there somewhere.  I've not used these a heck of a lot so I'm not sure.

Regan
« First   ‹ Prev
1 2
Top | Discussion index | About this forum | D home