farblog

by Malcolm Rowe

auto λ

Here’s a random thought: would it be useful for programming languages to provide a way to mark a function’s arguments such that expressions would be automatically converted (‘boxed’, if that’s not an overloaded term) to lambda expressions (anonymous inline functions) at the point of call?

Some background first: earlier today, Jon Skeet introduced me to the C# null-coalescing operator. For the uninitiated, this allows you to write something like:

string shipToAddress =
    order.shipToAddress ?? order.billingAddress ?? order.customer.address;

where shipToAddress will get set to the first non-null value of the three expressions listed. The ?? operator is therefore very much like the SQL COALESCE function, except that a C# or Java version of COALESCE — implemented as a regular function — would by necessity evaluate all the arguments before calling the function, and wouldn’t provide the short-circuit evaluation that makes the ?? (and &&, ||, etc) operators so useful.

Which led me to wonder: would it make sense for a C#/Java-like language to allow functions to declare that their arguments should be subject to deferred evaluation? This would not only allow me to write my own short-circuiting implementation of COALESCE (obviating the need to create yet-another-language-token), but also to write other variations as needed: return the first non-null-non-empty string, for example.

Jon pointed out that my concept of ‘deferred execution’ is exactly equivalent to converting the expression into a lambda expression at the point of call, which is probably an easier way to think about it. So I guess I’m imagining something like the following syntax (which also uses varargs, though the two concepts are orthogonal):

T coalesce(lambda<T> exprs...) {
  for (lambda<T> expr : exprs) {
    T result = expr.call();
    if (result != null) {
      return result;
    }
  }
  return null;
}

void foo() {
  string shipToAddress = coalesce(order.shipToAddress,
      order.billingAddress, order.customer.address);
}

Here lambda<T> is a type that is functionally (heh) similar to JavaScript’s Function type, providing a call() method that evaluates the expression and returns the result. The clever part (such that it is) would need to happen at the callsite — automatically wrapping each expression in an anonymous function.

One notable disadvantage with this syntax is that it is no longer possible to determine whether an expression is evaluated merely by looking at the callsite — obviously significant for expressions with side-effects.

In this respect, this is similar to the fact that you cannot tell whether the C++ statements X x; f(x); will result in the call f(x) mutating xf() will receive a copy of x or a reference to x, depending on whether the function is declared as void f(X x) or void f(X& x) (and typically C++ style guides will require that the latter is used only with a const modifier, precisely to avoid this kind of confusion).

C# avoids C++’s reference-or-value ambiguity by requiring the caller to use the ref keyword for pass-by-reference; Java by enforcing pass-by-value for all primitive types (and by not supporting value types); perhaps a similar approach for auto-lambda-boxing would sense, though it would be slightly awkward to have to write the Haskell-style:

string shipToAddress = coalesce(\order.shipToAddress,
    \order.billingAddress, \order.customer.address);

… which I suppose brings us full-circle as an argument for expressing behaviour like this via core language operators!