Anonymous Functions

Scott Waldron Updated by Scott Waldron

Anonymous functions can be a confusing topic, so a "quick start" is in order to explain the thinking behind them, and how they integrate with the host language.

Anonymous Functions Quick Start

Consider the following line of code.

var unwanted = sale.SaleItemList.FirstOrDefault(x => x.Item?.Name == 'ABCD');

Everything in the parentheses is what's known as an anonymous function, sometimes called an arrow function. If you look closely, that's not a greater-than-equal (>=), it's an "arrow" (=>). So basically, this code,

var unwanted = sale.SaleItemList.FirstOrDefault(x => x.Item?.Name == 'ABCD');
if unwanted {...}

would replace this,

var unwanted;
each x in sale.SaleItemList {
if x.Item?.Name == 'ABCD' {
unwanted = x;
break;
}
}
if unwanted {...}

To be more accurate, it is a nearly exact replacement for this:

// This function takes one parameter and returns true or false
def isUnwanted(x){
return x.Item?.Name == 'ABCD';
}

var unwanted;
each x in sale.SaleItemList {
if isUnwanted(x){
unwanted = x;
break;
}
}
if unwanted {...}

To break it down further...

  • x
    • This is the single parameter to the function. It can be any valid identifier; x is just a convention.
      • item => item.Item?.Name == 'ABCD'
    • Symbols to the left of the arrow is the parameter list that will be passed to the function.
  • =>
    • Points to the expression or block that will take x as the parameter
  • x.Item?.Name == 'ABCD'
    • The expression (which in this case results in true or false) and acts as the return value

So, there is still the question: what is the signature of FirstOrDefault(...) anyway? This is one of a series of methods that take an iterator function to iterate over a list. It looks something like this:

//
// This function takes two parameters:
// list: the list of objects to iterate over
// predicate: the function pointer (delegate) to the predicate function
// This will be called for each object in the list.
//

public static T FirstOrDefault<T>(this IEnumerable<T> list, Func<T, bool> predicate)
{
foreach(T item in list)
{
// Our predicate takes IN one parameter (a T) and returns a bool (true or false)
// Thus: Func<in T, out bool>
if(predicate(item))
{
// We found one, and we wanted the "first or default", so we can
// skip the rest and return the item.
return item;
}
}
// We never found a match using the predicate, so return null
return null;
}

Now in the case of SaleItemList, we are dealing with a list of SaleItem, that is List<SaleItem>. Since List<T> implements the IEnumerable<T> interface, that makes it able to call the FirstOrDefault(...) function. At runtime, the function would look like this to the compiler. Notice that all those T have been replaced with SaleItem.

public static SaleItem FirstOrDefault(
this IEnumerable<SaleItem> list,
Func<SaleItem, bool> predicate)
{
// ...
}

Now it's even a little more confusing, because you will notice that we don't pass SaleItemList to this function! That's because this is a special method called an extension method. Notice the "this" before the first parameter in FirstOrDefault(...). What that means is that the compiler will translate our code:

//                    |"this"|                  |"predicate"|        
var unwanted = sale.SaleItemList.FirstOrDefault(x => x.Item?.Name == 'ABCD');

into this:

//                                        |"this"|       |"predicate"|
var unwanted = Enumerable.FirstOrDefault(sale.SaleItems, x => x.Item?.Name == 'ABCD');

Enumerable is the class that defines the FirstOrDefault(...) method. So, we can call it this way if we want, but it's easier to just use it as an extension. Extension methods are just "syntactic sugar" They are compiled into normal static methods at compile time.

Different Number of Parameters

Sometimes an arrow function will take 0 parameters. In that case you must use (). Here is one that takes 0 params and returns a string:

var foo = something.GetSomething(() => 'Hello');

Sometimes it will take more than one parameter. Again, you must use (...):

var foo = something.Add((x, y) => x.Quantity + y.Quantity);

It's only in the case of a single parameter that you can omit the ().

Sometimes you need to do something way more complex in your function that just evaluate a single expression. In such a case, you need to use a block {...}.

// The block (function body) is in bold
var foo = something.Add((x, y) => {
// This is the body of our anonymous func
var xQty = x.Quantity;
var yQty = y.Quantity;

// Check inventory or something here. Send an email. Contact your congressman or woman.

return xQty + yQty;
}
);

Notice that in the case that we use a block, we must include a return statement. In the other cases, the naked expression is the return value.

Anonymous Functions in Dino

An anonymous function is simply a function that is defined without a name. Its syntax is slightly different than a standard def-type function. It is almost always assigned to a variable or passed as an argument to another function. Defining a stand-alone anonymous function is essentially pointless; its contents will never be evaluated.

Allowed but pointless.

(a, b) => {return a *b; };

Assign it to a variable.

var anon = (a, b) => {return a * b; };

Same as above, simpler syntax.

var anon = (a, b) => a * b;

For multiple statements, a block is required.

var anon = (a, b) => {
if a > 10 {
return a;
}
return a * b;
}; // note the semicolon here to end the variable assignment

Super simple with only one argument, no () required.

var squareIt = a => a * a;

With no args, you must use ().

var divide10by2 = () => {return 10 / 2};

With multiple args, you must use ().

var anon = (x, y, z) => x * y + z;

Anonymous functions are called just like any other.

var doubleIt = x => x + x;
print(doubleIt(10)); // 20

Wait, what do you mean “without a name”? Isn’t the name declared in all those previous examples? No, the assigned name is the name of a variable to which we are assigning the anonymous function. In other words, we are declaring a variable which has as an anonymous function as its value.

To better illustrate this, consider the following example: you do not have to pre-declare anonymous functions – sometimes you just want to use them in-place as an argument to a function.

// a regular Dino function
def rex(callback, a) {
return callback(a) + 10;
}

// Pass an anonymous function to another function as arg
// In this example the "anonymity" of the function is more obvious
rex(a => a * 2, 5); // 20

Often, anonymous functions are used to pass delegates to the host language. Using an anonymous function in this way is often referred to as a callback, because when the arguments are evaluated in the other function, the other function will “call back” to the anonymous function for evaluation.

from System import 'Func`2' as F2;
from System.Linq import Enumerable;

var myList = list(4, 5, 6);

// value type delegate requires explicit cast
var add1 = myList.Select(F2[int, int](x => x + 1)).ToList(); // 5, 6, 7

Dino does not support immediate anonymous function execution. Some languages, such as JavaScript, do support this feature. At best, it saves a tiny amount of typing – and it confuses most people because the syntax looks bizarre.

var anon = (a, b) => {return a + b}(3, 4); // error
// needs to be rewritten as...
var anon = (a, b) => {return a + b};
anon(3,4);

How did we do?

Custom Functions (defs)

Conditional Statements

Contact