Programming in Dart: Functions & Closures

Jun 21 2022 · Dart 2.16, Flutter, DartPad

Part 1: Meet the Function

06. Store a Function

Episode complete

Play next episode

Next
About this episode
Leave a rating/review
See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 05. Challenge: Create a Function Next episode: 07. Understand Typedef

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Transcript: 06. Store a Function

Functions are a great way to call code on demand. One convenient aspect of functions is that we can store them in variables and pass them around to other functions. In the second part of this course, you’ll see this in action. But for now, just know this is a great way to create dynamic and adaptable programs.

A function is known as a first class citizen. It’s like any other type. You can pass it around as parameters, return them from other functions and assign it to variables.

When you define a variable, you need to give it a type. A function is a function type. So to store a function in a variable, you need to give it a function.

At which point, you can assign a function like any other value. For instance, here I am assigning the print function to my variable. Notice that when I do this, I just provide the function name and nothing else.

Let’s see how we can use functions in variables.

To get started, open up DartPad in a browser. We’re going to start with a multiplication function. This function takes in two integers and then returns an integer.

int multiply(int a, int b) {
    return a * b;
}

Now, let’s put our multiply function to the test. We will multiply ten times times.

print(multiply(10, 10));

When we run the code, you see that it prints out one hundred to the console. Now lets store this function in a variable. We’ll call this myFunction.

var myFunction = print();

Now we can assign the function. Simply write the function’s name after the equals sign.

var myFunction = multiply;

Run the code. It does the same exact thing.

As you can see, it’s not hard storing a function in a variable. But what if you want to pass it into a function? You can define a parameters as a function and call it like an normal function. Things get difficult when that function returns a value since Dart won’t know the return type until run time.

We’re going pass in a function to another function. First, let’s define a list of integers.

void main() {
    var scores = [54, 75, 32];
}

Now lets define a function that process scores. We’ll call it processScores. It will take a list of integers, and a function.

int processScores(List<int> scores, Function processor) {

}

Here we’ve defined a function that we’re ready to use. Let’s define the rest of the function. We’ll define a total variable that will store the result of the function and return it.

int processScores(List<int> scores, Function processor) {
    var total = 0;

    return total;
}

Now lets loop through the list and run our passed in function.

for (var score in scores) {
    var number = processor(score, 2);
}

If you click on the number, you’ll see that it’s dynamic. Dynamic is Dart’s catch-all type. It means, the result can be anything. It can’t be checked at compile time. Let’s try adding it to the total.

total += number;

Unfortunately, this produces an error since Dart can’t guarantee we’re dealing with a number. For instance, you might pass in a function that returns a string. We have to perform what is known as a cast. That is, we want to convert our dynamic into an integer. Delete the previous line. Now, add the following:

total += (number is int) ? number : 0;

This little line does a lot. Dart first checks to see if the number variable is an int. If it is an int, it converts it to number and adds to the total variable. Otherwise, it returns zero which is added to the total.

Honestly, this is a line of code that makes sense now, but may be absolutely confusing down the road. This is something I’d avoid in my code. To avoid this, we can define our function in the parameter. Update the signature to the following:

int processScores(List<int> scores, int Function(int, int) processor) {

This defines a function parameter. This function takes in two ints and returns an int although it looks somewhat strange. Now we can update our looping code the following:

for (var score in scores) {
    total += processor(score, 2);
}

Since the function returns an int, we don’t need to perform a cast operation. Let’s now call our function in the main function. First, lets get rid of the other code, then call our code.

void main() {
  var scores = [54, 75, 32];
  print(processScores(scores, multiply));
}

Run the program and you’ll see the result. This works and it avoids the casting but does make for a complex function header. We can actually fix that which we’ll be doing in the next episode.