Sam has a
very nice piece on bringing the old-school C heads into the world of continuations.
I for one fell in love with this style of programming when the first Whidbey C# compilers started appearing a couple of years ago.
Here's Sam's Fibonacci program in C# 2.0:
class Program
{
public static IEnumerable<long> fib()
{
yield return 0;
long i = 0, j = 1;
while (true)
{
yield return j;
long temp = i;
i = j; j = temp + j;
}
}
static void Main(string[] args)
{
foreach (long n in fib())
{
if (n > 1000)
break;
Console.WriteLine(n);
}
}
}
Except for the obvious syntactic differences, it's pretty much the same as the Ruby program (insert snide comment about how much cooler Ruby's assignment statement is).
I remember when the feature first showed up, people got pretty wild. I recall implementing a coroutine-like scheduler that modeled sequential execution as a series of yield return statements. Unusable in practice (at least my implementation) but cute.
The underlying language feature (along with its cousin, anonymous methods) do in fact rock though.
Here's the same program written using anonymous methods:
class Program
{
public delegate T Function<T>();
public static Function<long> fib2()
{
long i = 0, j = 1;
return delegate()
{
long result = i;
i = j;
j = result + j;
return result;
};
}
static void Main(string[] args)
{
Function<long> f = fib2();
while (true)
{
long n = f();
if (n > 1000)
break;
Console.WriteLine(n);
}
}
}
This program has the same characteristics as the iterator version. Calling the fib or fib2 function causes a heap-allocated frame to be created that keeps track of the particular activation of that frame.
One interesting thing about anonymous methods is that one can do Javascript-like prototype/instance stuff like this:
class Program
{
public delegate T Function<T1, T>(T1 arg);
public enum Op
{
Add, Subtract, Multiply, Divide
}
public static Function<decimal, decimal>[] CreateCalculator()
{
decimal value = 0;
return new Function<decimal, decimal>[] {
delegate (decimal arg) { value += arg; return value; },
delegate (decimal arg) { value -= arg; return value; },
delegate (decimal arg) { value *= arg; return value; },
delegate (decimal arg) { value /= arg; return value; },
};
}
static void Main(string[] args)
{
Function<decimal, decimal>[] calc = CreateCalculator();
calc[(int)Op.Add](3);
calc[(int)Op.Multiply](7);
calc[(int)Op.Subtract](1);
decimal result = calc[(int)Op.Divide](4);
Console.WriteLine(result);
}
}
It may be a bit early to write off named class definitions, but it's nice that these ideas are easily expressible.
Posted
Apr 17 2005, 05:36 PM
by
don-box