Implementing returns without using the DLR for scoping/closures

Jan 8, 2010 at 11:30 PM
Edited Jan 8, 2010 at 11:31 PM

So, over the last few threads I've managed to solve a bunch of different problems, it's been an awesome journey - but here I am again, this time it's about implementing a return statement without using the built in scoping and closures of the DLR, I think I have a working design, I just want to see that I'm on the right track.

I'm not using the built in scoping/closure functionality of the DLR, but basically the idea I had was this (I'm assuming I can't use labels because I'm lifting all the functions to a global function table, and they have no sense of scope amongst each other): Pass in a hidden parameter at beginning of the argument list for each lambda (sort of like an implicit this variable for objects, etc.), so assuming I had some code in my language that looks like this:

int foo(bar) {
	if(bar % 2 == 0) {
		return pow(bar, 2);
	} else {
		return bar * 2;	
	}
}

print(foo(5));

This would get compiled into the following:

void foo(_ret, bar) {
	if(bar % 2 == 0) {
		_ret.value = pow(bar, 2);
		goto: exit;
	} else {
		_ret.value = bar * 2;	
		goto: exit;
	}

	label: exit;
}

_foo_ret = new RefCell();
foo(5, _foo_ret)
print(_foo_ret.value);

(Excuse my semi-pseudo-code-something-something, I hope it's understandable)

Is this a proper way to  handle returning in the DLR? I'm assuming I can't use labels because my language (finally) has it's own scoping and handling of closures, etc. If this isn't a good way to handle it, how should I approach it? can I maybe use the "normal" Expression.Return() and Expression.Label() (I can't see how, but then again I'm not very good at this) ?

Jan 9, 2010 at 12:14 AM
Edited Jan 9, 2010 at 12:15 AM

The value of lambda's body is its return value. So you can just write this: 

            var bar = Expression.Parameter(typeof(int), "bar");

            var l = Expression.Lambda<Func<int, int>>(
                Expression.Condition(
                    Expression.Equal(Expression.Modulo(bar, Expression.Constant(2)), Expression.Constant(0)),
Expression.Multiply(bar, Expression.Constant(10)),
Expression.Multiply(bar, Expression.Constant(20))
),
new[] { bar } );
You don't need gotos in this case.

Return is just a goto jumping to the end of the function as you have in above code. A goto can carry a value that becomes the value of the target label.

So you can also write:

            var bar = Expression.Parameter(typeof(int), "bar");
            var label = Expression.Label(typeof(int));

            var l = Expression.Lambda<Func<int, int>>(
                Expression.Block(
                    Expression.Condition(
                        Expression.Equal(Expression.Modulo(bar, Expression.Constant(2)), Expression.Constant(0)),
                        Expression.Return(label, Expression.Multiply(bar, Expression.Constant(10))),
                        Expression.Return(label, Expression.Multiply(bar, Expression.Constant(20)))
                    ),
                    Expression.Label(label, Expression.Default(typeof(int)))
                ),
                new[] { bar }
            );