I went with C# lambda style syntax, since that does tend to be cleaner and a little less ambiguous for the parser than alternatives. Unfortunately, Tangent can't (nicely) support the type inference C# allows on params and on return type. So the Tangent syntax is a bit more verbose:
( method-parameter-list ) => return-type-expression block
It kinda sucks, because the verbosity might push people away from its use. And it will likely turn away functional language advocates who like things nice and succinct. I dislike succinctness in languages, but x => x + 1; is pretty damned clear.
Making the lambdas work required only a few changes. The syntax itself is constructed of bits already used elsewhere. When the lambda's block is compiled, the lambda's scope is simply added to the stack of scopes for name resolution. The name resolution got an added snippet of code to tack on a 'use the outer scope' placeholder (for locals/params/member vars in the outer method). That placeholder then becomes a VM opcode (access outer-scope) during compilation. The lambda itself is compiled into its own VM opcode that creates the method instance and binds the outer scope (params, calling-instance, locals) with it.
This should emulate C#'s closure behavior (and it's a bug if it doesn't), such as weird stuff like this:
void foo(){ int x = 0; someDelegate = ()=>{Console.WriteLine(x);}; x = 1000;}foo();someDelegate(); // 1000!
And now for some (mildly ugly) test-code:
public class foo{ public delegate bool Conditional(int x); public delegate void Action(int x); public void Process(int x){ if( Conditional(x) ){ Action(x); } }}public static void main(){ local foo A = new foo; local foo B = new foo; A.Conditional = (int x)=>bool{ return(x<10); }; A.Action = (int x)=>void{ print "A:" x " \r\n"; }; B.Conditional = (int x)=>bool{ return(x==42); }; B.Action = (int x)=>void{ print "B!\r\n"; }; A.Process(4); A.Process(42); B.Process(4); B.Process(42);}// A:4// B!
Binary parameter lambdas can be used as operators (not recommended) or stored in an operator delegate (more recommended). I will be providing a mechanism for combining them (and other arbitrary methods) into a method group, which should yield the ability to do stuff akin to pattern matching found in functional languages (as well as mildly nifty polymorphism on event-handling).
Next in the queue should be Properties. Though Disgaea 3 is coming out next week. Productivity that doesn't involve joyously evil tactical role playing is likely to decline precipitously.
P.S. The syntax is still more than terse enough and not verbose at all. I like it. And Im picky too since as scooby would say, icchh. I hate verbosity.
I see a gotcha in this code. SomeDelegate should technically not be visible outside of foo. It has escaped its scope. I assume you're just testing though.
What does this do?