Chapters

Hide chapters

Dart Apprentice: Fundamentals

First Edition · Flutter · Dart 2.18 · VS Code 1.71

Dart Apprentice: Fundamentals

Section 1: 16 chapters
Show chapters Hide chapters

7. Functions
Written by Jonathan Sande

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Each week, there are tasks that you repeat over and over: eat breakfast, brush your teeth, write your name, read books about Dart, and so on. Each of those tasks can be divided up into smaller tasks. Brushing your teeth, for example, includes putting toothpaste on the brush, brushing each tooth and rinsing your mouth out with water.

The same idea exists in computer programming. A function is one small task, or sometimes a collection of several related tasks, that you can use in conjunction with other functions to accomplish a larger task. In this chapter, you’ll learn how to write functions in Dart.

Function Basics

You can think of functions like machines. They take something you provide to them, the input, and produce something different, the output.

Function Input Output

There are many examples of this in daily life. With an apple juicer, you put in apples and you get out apple juice. The input is apples; the output is juice. A dishwasher is another example. The input is dirty dishes, and the output is clean dishes. Blenders, coffee makers, microwaves and ovens are all like real-world functions that accept an input and produce an output.

Don’t Repeat Yourself

Assume you have a small, useful piece of code that you’ve repeated in multiple places throughout your program:

// one place
if (fruit == 'banana') {
  peelBanana();
  eatBanana();
}

// another place
if (fruit == 'banana') {
  peelBanana();
  eatBanana();
}

// some other place
if (fruit == 'banana') {
  peelBanana();
  eatBanana();
}

Anatomy of a Dart Function

In Dart, a function consists of a return type, a name, a parameter list in parentheses and a body enclosed in braces.

Vlsurw kofvhiyonw (ujm vurcid) { } '$zestic oq o gelj goni xuhjum.'; jugevb Bavuhc femea Sozurt vlye Hehehunip xcri Waxdkuif nupi Xirekaxan qari

String compliment(int number)
{
  return '$number is a very nice number.';
}
void main() {
  const input = 12;
  final output = compliment(input);
  print(output);
}

String compliment(int number) {
  return '$number is a very nice number.';
}
12 is a very nice number.

Parameters

Parameters are incredibly flexible in Dart, so they deserve their own section.

Using Multiple Parameters

In a Dart function, you can use any number of parameters. If you have more than one parameter for your function, simply separate them with commas. Here’s a function with two parameters:

void helloPersonAndPet(String person, String pet) {
  print('Hello, $person, and your furry friend, $pet!');
}
helloPersonAndPet('Fluffy', 'Chris');
// Hello, Fluffy, and your furry friend, Chris!

Making Parameters Optional

The function above was very nice, but it was a little rigid. For example, try the following:

helloPersonAndPet();
2 positional argument(s) expected, but 0 found.
String fullName(String first, String last, String title) {
  return '$title $first $last';
}
String fullName(String first, String last, [String? title]) {
  if (title != null) {
    return '$title $first $last';
  } else {
    return '$first $last';
  }
}
print(fullName('Ray', 'Wenderlich'));
print(fullName('Albert', 'Einstein', 'Professor'));
Ray Wenderlich
Professor Albert Einstein

Providing Default Values

In the example above, you saw that the default value for an optional parameter was null. This isn’t always the best value for a default, though. That’s why Dart also gives you the power to change the default value of any parameter in your function by using the assignment operator.

bool withinTolerance(int value, [int min = 0, int max = 10]) {
  return min <= value && value <= max;
}
withinTolerance(5)  // true
withinTolerance(15) // false
withinTolerance(9, 7, 11) // true
withinTolerance(9, 7) // true

Naming Parameters

Dart allows you to use named parameters to make the meaning of the parameters more clear in function calls.

bool withinTolerance(int value, {int min = 0, int max = 10}) {
  return min <= value && value <= max;
}
withinTolerance(9, min: 7, max: 11) // true
withinTolerance(9, min: 7, max: 11) // true
withinTolerance(9, max: 11, min: 7) // true
withinTolerance(min: 7, max: 11, 9) // true
withinTolerance(min: 7, 9, max: 11) // true
withinTolerance(5)           // true
withinTolerance(15)          // false

withinTolerance(5, min: 7)   // false
withinTolerance(15, max: 20) // true

Making Named Parameters Required

You might like to make value a named parameter as well. That way you could call the function like so:

withinTolerance(value: 9, min: 7, max: 11)
withinTolerance()
bool withinTolerance({
  required int value,
  int min = 0,
  int max = 10,
}) {
  return min <= value && value <= max;
}

Exercises

  1. Write a function named youAreWonderful, with a string parameter called name. It should return a string using name, and say something like “You’re wonderful, Bob.”
  2. Add another int parameter to that function called numberPeople so that the function returns something like “You’re wonderful, Bob. 10 people think so.”
  3. Make both inputs named parameters. Make name required and set numberPeople to have a default of 30.

Writing Good Functions

People have been writing code for decades. Along the way, they’ve come up with some good practices to improve code quality and prevent errors. One of those practices is writing DRY code as you saw earlier. Here are a few more things to pay attention to as you learn about writing good functions.

Avoiding Side Effects

When you take medicine to cure a medical problem, but that medicine gives you a headache, that’s known as a side effect. If you put some bread in a toaster to make toast, but the toaster burns your house down, that’s also a side effect. Not all side effects are bad, though. If you take a business trip to Paris, you also get to see the Eiffel Tower. Magnifique!

Digmcout Oxsuy Iiygos Zese opjixcf

void hello() {
  print('Hello!');
}
String hello() {
  return 'Hello!';
}
var myPreciousData = 5782;

String anInnocentLookingFunction(String name) {
  myPreciousData = -1;
  return 'Hello, $name. Heh, heh, heh.';
}

Doing Only One Thing

Proponents of “clean code” recommend keeping your functions small and logically coherent. Small here means only a handful of lines of code. If a function is too big, or contains unrelated parts, consider breaking it into smaller functions.

Choosing Good Names

You should always give your functions names that describe exactly what they do. If your code sounds like well-written prose, it’ll be faster to read and easier to understand.

Optional Types

Earlier you saw this function:

String compliment(int number) {
  return '$number is a very nice number.';
}
compliment(number) {
  return '$number is a very nice number.';
}
String compliment(dynamic number) {
  return '$number is a very nice number.';
}

Arrow Functions

Dart has a special syntax for functions whose body is only one line. Consider the following function named add that adds two numbers together:

int add(int a, int b) {
  return a + b;
}
int add(int a, int b) => a + b;
void printTripled(int number) {
  final tripled = number * 3;
  print(tripled);
}
void printTripled(int number) => print(number * 3);

Challenges

Before moving on, here are some challenges to test your knowledge of functions. It’s best if you try to solve them yourself, but solutions are available in the challenge folder for this chapter if you get stuck.

Challenge 1: Circular Area

Write a function that tells you the area of a circle based on some input radius. If you recall from geometry class, you can find the area of a circle by multiplying pi times the radius squared.

Challenge 2: Prime Time

Write a function that checks if a number is prime.

bool isNumberDivisible(int number, int divisor)
bool isPrime(int number)
isPrime(6); // false
isPrime(13); // true
isPrime(8893); // true
import 'dart:math';

Key Points

  • Functions package related blocks of code into reusable units.
  • A function signature includes the return type, name and parameters. The function body is the code between the braces.
  • Parameters can be positional or named, and required or optional.
  • Side effects are anything besides the return value that change the world outside of the function body.
  • To write clean code, use functions that are short and only do one thing.

Where to Go From Here?

This chapter spoke briefly about the Single Responsibility Principle and other clean coding principles. Do a search for SOLID principles to learn even more. It’ll be time well spent.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2024 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now