Search code examples
c#pass-by-name

Arguments passed "by name" in C#


The Scala programming language has a neat feature, called pass by name arguments, that allows some arguments to only be evaluated if required.

For example, it's possible to write a while loop using a curried method such as the following:

// This is Scala code. A simulated while loop
@scala.annotation.tailrec
def myWhile(condition: => Boolean)(actions: => Unit): Unit = {
  if(condition) {
    actions
    myWhile(condition)(actions)
  }
}

This method can be used like a regular while loop, thanks to Scala's syntactic sugar, closures and—of particular interest here—the ability to pass expressions as function arguments, which are evaluated when referenced (as indicated by the : => type argument declaration).

For example, the following prints "Hello!" to the console ten times:

var i = 0
myWhile(i < 10) {
  println("Hello!")
  i += 1
}

For those who need to understand what is happening, the expression i < 10 is evaluated each time condition appears inside the if(...) statement inside the method, similarly, println("Hello!"); i += 1 is evaluated each time actions appears in the body of the method. When recursively calling myWhile for the next iteration, the expressions are passed as is, since the method requires expressions, not values. Scala terms these pass by name arguments.

If these arguments were passed by value instead, then i < 10 would be passed to myWhile as false, while "Hello!" would be printed exactly once, i would be incremented once, and the loop would execute infinitely.

(Scala is primarily a functional language, and this code is not even close to being FP, but it's a simple example.)

My question is, is there a way to pass arguments in this way to a C# function? Also note that I'm restricted to using C# 7.3. :-(


Solution

  • It sounds like you can get somewhat close with Func`1 and Action:

    void MyWhile(Func<bool> condition, Action action) {
      while (condition()) {
        action();
      }
    }
    

    and calling as:

    int i = 0;
    MyWhile(() => i < 10, () => {
      Console.WriteLine("Hello!");
      ++i;
    });
    

    The syntax is a bit different, but the idea is similar.