Aug 03

Continued: Simple concurrent evaluation strategies in mainstream languages

Tag: Code, Computer Science, ProgrammingAdam Wright @ 12:39 am

Last time, we outlined an evaluation strategy known as “Call-by-future” and determined that it might (just might!) be useful in adding an easy to use concurrency feature to mainstream languages. Now we’re resolved to implement it, what features should we be aiming for in our implementation?

  1. Easy to understand – the solution we come up with must be understandable by as many people as possible. This goes without saying for all code – we don’t want to create an un-maintainable monster that no one touches in their fear.
  2. Type safety – We don’t want to throw away existing safeguards just to get a bit of convenience, as we’ll likely end up introducing bugs when using it.
  3. Easy to begin using it in existing codebases – The point of this exercise was to come up with something people can use here and now, and just jump in with. If it requires a whole program redesign or an entirely new way of thinking, we’ve probably not done all that well.

So, how do we envisage this working? To comply with rule number 3 above, we want something that behaves as closely to normal parameter passing as it can – only we control the execution. Ideally, we’d be able to declare Foo using something like void Foo(callbyfuture int a) or similar, to indicate that the parameter would be evaluate using our call by future-by-future evaluation. Alas, we can’t add keywords to the complier – but – we can add types. How about void Foo(CallByFuture a)? We’re using the generics system to construct a CallByFuture type, indicating that the parameter evaluates to an int; this fulfils our 2nd requirement (type safety).

The other thing we need to do is find some method of “taking control” of parameter evaluation. That is, if I use the expression Foo(Bar()) in a C# program, the compiler will invoke it’s normal evaluation strategy and emit code that will first evaluate bar, then pass the result either by value or reference to Foo. We need to be able to step in and say “Whoa, don’t evaluate Bar() just yet – hold off!” so that we can evaluate it in the way we want without confusing the compiler.

Whilst we can’t control expression evaluation in general, we can control the evaluation of a group of expressions via a .net delegate (effectively a function pointer) – any list of expressions wrapped in a delegate, we can call “at will”. Now, manually creating a new delegate for every single parameter we wish to evaluate using call-by-future would be tedious in the extreme, and hence violate both rules 1 and 3 above. Luckily, in C# 2.0, a new feature was added – anonymous delegates. Using these, creating an “expression” whose evaluation we can control becomes as simple as delegate { return (expr); }. Not ideal, but fairly terse (and flexible – as we’ll soon see).

Having discussed how we see this all working, let’s head off and have the boring keyboard bashing session. Return soon for part 3, when we’ll have finished the implementation and be ready to take it for a road test!

Leave a Reply