Watch the video (9 min)
On this page24 sections
  1. Prerequisites
  2. Connection With Previous Lectures
  3. Learning Objectives
  4. 1. What Is a Function?
  5. 2. Defining a Function
  6. 3. Calling a Function
  7. 4. Call It As Often As You Like
  8. 5. What void Means
  9. 6. main() Is a Function Too
  10. 7. The Empty ()
  11. 8. Order of Definitions Does Not Matter
  12. 9. Calling One Function from Another
  13. 10. Variables Inside a Function Belong to It
  14. 11. Functions That Change Top-Level Variables
  15. 12. A Real-World Example
  16. Code Examples
  17. Common Beginner Mistakes
  18. Best Practices
  19. Mini Challenge
  20. Practice Questions
  21. Practice Answers
  22. Quick Revision
  23. Key Takeaways
  24. What's Next?

Lecture 30 — Introduction to Functions

Category6 — Functions
Lecture030 of 140
Estimated video length9 min
TargetDart 3.12.2
LevelBeginner

Until now every program was one long main(). A function gives a block of code a name, so you write it once and run it whenever you call that name.

Contents

Prerequisites · Connection · Objectives · Lesson · Code Examples · Common Mistakes · Best Practices · Mini Challenge · Practice Questions · Answers · Takeaways

Every error message in this lecture is real. Each one was produced by running the code shown on Dart 3.12.2, so you will recognize it when you meet it yourself.


Prerequisites

Students should already understand, from Lectures 003–029:

  • void main() { … }, print(), and comments (Lecture 003)
  • variables, var, final, and top-level variables (Lectures 004–006)
  • string interpolation and arithmetic operators (Lectures 008 and 017)
  • nullable types and type promotion (Lectures 013 and 016)
  • if statements and for loops (Lectures 022 and 026)

Connection With Previous Lectures

Every program so far has lived inside main(). Suppose a shop prints a header above every receipt:

dart
void main() {
  print('==========');
  print('ALI STORE');
  print('==========');
  print('Notebook: 500');

  print('==========');
  print('ALI STORE');
  print('==========');
  print('Pen: 40');
}

The three header lines are typed twice. With ten receipts they would be typed ten times — and if the shop renamed itself, you would edit ten places and probably miss one. A loop does not help, because the lines between the headers are different each time. What we need is a way to give those three lines a name and say "run them again" whenever we like. That is a function.


Learning Objectives

By the end of this lecture you will be able to:

  • Understand what a function is and why programs use them
  • Define a function with void, a name, (), and a body
  • Call a function, as many times as you need
  • Explain what void means
  • Recognize main() as a function that Dart calls for you
  • Call one function from inside another and follow the order the lines run
  • Use functions to read and change top-level variables
  • Recognize the error messages Dart gives for common function mistakes

1. What Is a Function?

A function is a named block of code that runs when you ask for it.

Analogy — a function is like a recipe card. Writing the card does not cook anything. Cooking happens each time someone says "make the pancakes" — and they can say it as often as they want without rewriting the recipe.

You have used functions since Lecture 003: print() is one. Someone else wrote the code that puts text on the screen; you just call it by name. Today you write your own.


2. Defining a Function

Here is the receipt header as a function:

dart
void printHeader() {
  print('==========');
  print('ALI STORE');
  print('==========');
}
PartMeaning
voidthe function gives nothing back (section 5)
printHeaderthe function's name, in lowerCamelCase
()the parameter list — empty here (section 7)
{ … }the body: the statements that run

This is called a function definition (or declaration). It is written outside main(), at the top level of the file, just like the top-level variables in Lecture 004.


3. Calling a Function

A definition alone does nothing. To run the body you call the function: write its name followed by () and a semicolon.

dart
void printHeader() {
  print('==========');
  print('ALI STORE');
  print('==========');
}

void main() {
  printHeader();
  print('Notebook: 500');
}
output
==========
ALI STORE
==========
Notebook: 500

When Dart reaches printHeader();, it jumps into the body, runs every line, then comes back and continues with the next line of main().


4. Call It As Often As You Like

The whole point: one definition, many calls.

dart
void printHeader() {
  print('==========');
  print('ALI STORE');
  print('==========');
}

void main() {
  printHeader();
  print('Notebook: 500');
  printHeader();
  print('Pen: 40');
}
output
==========
ALI STORE
==========
Notebook: 500
==========
ALI STORE
==========
Pen: 40

This is the receipt program from the Connection, without the copy-paste. Rename the store inside printHeader() and both receipts change.


5. What void Means

void means "this function does its job and gives nothing back". printHeader() prints — that is its whole job — and there is no result to hand to the caller.

Because there is nothing, Dart refuses to let you use a void call as a value:

dart
void printHeader() {
  print('ALI STORE');
}

void main() {
  print(printHeader()); // ✗
}
output
Error: This expression has type 'void' and can't be used.
  print(printHeader());
        ^

A preview. A function can also hand a value back. Then its definition starts with the value's type instead of void, and it uses the keyword return:

dart
String storeName() {
  return 'ALI STORE';
}

void main() {
  print(storeName());
}
output
ALI STORE

We will study return and functions that produce values in Lecture 031 — Parameters & Return Values. In this lecture every function we write is void.


6. main() Is a Function Too

Look at void main() { … } again — it has exactly the same shape as printHeader(). main is a function. The only difference is who calls it: you never write main(); yourself. When you run a file, Dart calls main() for you, and when main() finishes, the program ends.

dart
void sayGoodbye() {
  print('Goodbye!');
}

void main() {
  print('main starts');
  sayGoodbye();
  print('main ends');
}
output
main starts
Goodbye!
main ends

So a Dart program is a set of functions, and main() is the one where everything begins. That is why the program in Lecture 003 refused to start when main was misspelled.


7. The Empty ()

The brackets after the name are the function's parameter list — the spot where a function can receive information from its caller. Every function so far needs nothing, so the brackets are empty, both where you define it and where you call it.

The brackets are never optional, even when empty. void printHeader { is a syntax error, and calling printHeader without () does not run it (see Common Mistakes).

We will fill the brackets — so one function can greet Ali, Sara, or Zayan — in Lecture 031.


8. Order of Definitions Does Not Matter

A top-level function can be written above main() or below it. Dart reads the whole file before running anything, so it already knows every function's name.

dart
void main() {
  printFooter();
}

void printFooter() {
  print('Thank you for shopping!');
}
output
Thank you for shopping!

What matters is the order of the calls inside main(), not the order of the definitions in the file. A common style is main() first, then the functions it uses.


9. Calling One Function from Another

A function body can call other functions — that is how large programs are built from small pieces.

dart
void main() {
  printReceipt();
}

void printReceipt() {
  printHeader();
  print('Notebook: 500');
  printFooter();
}

void printHeader() {
  print('== ALI STORE ==');
}

void printFooter() {
  print('Thank you!');
}
output
== ALI STORE ==
Notebook: 500
Thank you!

Follow the path: Dart calls main() → main() calls printReceipt() → that calls printHeader(), comes back, prints the item, calls printFooter(), comes back → returns to main(), which has nothing left, so the program ends. Each call always returns to the exact spot it came from.


10. Variables Inside a Function Belong to It

A variable declared inside a function's body is a local variable. It exists only while that function runs, and other functions cannot see it:

dart
void setDiscount() {
  int discount = 50;
  print('Discount set: $discount');
}

void main() {
  setDiscount();
  print(discount); // ✗
}
output
Error: Undefined name 'discount'.
  print(discount);
        ^^^^^^^^

discount belongs to setDiscount() alone. We will study scope in detail in Lecture 037 — Closures & Scope.


11. Functions That Change Top-Level Variables

A top-level variable, declared outside every function, can be read and changed by every function in the file. That lets a no-parameter function update shared data:

dart
double balance = 1000;

void depositSalary() {
  balance += 500;
}

void payRent() {
  balance -= 700;
}

void main() {
  depositSalary();
  payRent();
  print('Balance: $balance');
}
output
Balance: 800.0

This is the promise from Lecture 016. A top-level nullable variable is never promoted, because any function could set it back to null between two lines of main():

dart
String? nickname = 'Ali';

void forgetNickname() {
  nickname = null;
}

void main() {
  if (nickname != null) {
    forgetNickname();
    print(nickname); // prints null — the check is already stale
  }
}
output
null

The if checked nickname before forgetNickname() ran. Dart cannot be sure that no call changes a top-level variable, so it keeps the type String?. That is the reason behind the rule you learned in Lecture 016.

late can also delay a calculation until a value is first needed (Lecture 006). That needs a function that returns a value, so it waits for Lecture 031.


12. A Real-World Example

A student report card, split into small named jobs:

dart
String student = 'Sara';
int total = 0;

void main() {
  printTitle();
  addMarks();
  printResult();
}

void printTitle() {
  print('--- Report Card ---');
  print('Student: $student');
}

void addMarks() {
  total += 80; // math
  total += 75; // science
  total += 85; // English
}

void printResult() {
  print('Total: $total / 300');
  if (total >= 200) {
    print('Result: Pass');
  }
}
output
--- Report Card ---
Student: Sara
Total: 240 / 300
Result: Pass

main() now reads like a table of contents: title, marks, result. Each function does one job, and its name says what that job is.


Code Examples

Example 1 — Define and Call

dart
void greet() {
  print('Hello, Ali!');
}

void main() {
  greet();
}
output
Hello, Ali!

Example 2 — One Function, Three Calls

dart
void printLine() {
  print('----------');
}

void main() {
  printLine();
  print('Sara');
  printLine();
}
output
----------
Sara
----------

Example 3 — Defined Below main()

dart
void main() {
  showRules();
}

void showRules() {
  print('Rule 1: Be on time.');
  print('Rule 2: Be kind.');
}
output
Rule 1: Be on time.
Rule 2: Be kind.

Example 4 — Order of Execution

dart
void middle() {
  print('2');
}

void main() {
  print('1');
  middle();
  print('3');
}
output
1
2
3

Example 5 — A Function Calling Functions

dart
void main() {
  morningRoutine();
}

void morningRoutine() {
  wakeUp();
  eatBreakfast();
}

void wakeUp() {
  print('Zayan wakes up.');
}

void eatBreakfast() {
  print('Zayan eats breakfast.');
}
output
Zayan wakes up.
Zayan eats breakfast.

Example 6 — Calling Inside a Loop

dart
void cheer() {
  print('Hip hip hooray!');
}

void main() {
  for (var i = 0; i < 3; i++) {
    cheer();
  }
}
output
Hip hip hooray!
Hip hip hooray!
Hip hip hooray!

Example 7 — Student Marks

dart
int marks = 72;

void main() {
  addBonus();
  printMarks();
}

void addBonus() {
  marks += 5;
}

void printMarks() {
  print('Ali scored $marks');
}
output
Ali scored 77

Example 8 — Shopping Total

dart
int total = 0;

void main() {
  addNotebook();
  addNotebook();
  addPen();
  print('Total: $total');
}

void addNotebook() {
  total += 500;
}

void addPen() {
  total += 40;
}
output
Total: 1040

How it works

  1. total is top-level, so both functions can change it.
  2. addNotebook() runs twice (+500 each time), addPen() once (+40).
  3. main() prints the result: 1040.

Example 9 — Bank Balance

dart
double balance = 1000;

void main() {
  printBalance();
  withdraw200();
  printBalance();
}

void withdraw200() {
  balance -= 200;
  print('Withdrew 200');
}

void printBalance() {
  print('Balance: $balance');
}
output
Balance: 1000.0
Withdrew 200
Balance: 800.0

Example 10 — Temperature Report

dart
double celsius = 25;

void main() {
  printCelsius();
  printFahrenheit();
}

void printCelsius() {
  print('Celsius: $celsius');
}

void printFahrenheit() {
  double fahrenheit = celsius * 9 / 5 + 32;
  print('Fahrenheit: $fahrenheit');
}
output
Celsius: 25.0
Fahrenheit: 77.0

How it works

  1. celsius is top-level, so both functions can read it.
  2. fahrenheit is local to printFahrenheit() — no other function can see it.
  3. main() simply decides the order: Celsius first, then Fahrenheit.

Common Beginner Mistakes

1. Defining a function but never calling it

dart
void greet() {
  print('Hello!');
}

void main() {
  print('Done');
}
output
Done

No error — Hello! just never appears. A definition is a recipe card; nothing cooks until you call greet();.

2. Forgetting the () when calling

dart
// void main() {
//   greet; // ✗ names the function but does not call it
// }

This is the sneakiest mistake: it compiles, runs, and does nothing — with the default settings neither dart run nor dart analyze complains. Always write greet();.

3. Misspelling the name in a call

dart
// void printHeader() {
//   print('ALI STORE');
// }
//
// void main() {
//   printHedaer(); // ✗
// }
output
Error: Method not found: 'printHedaer'.
  printHedaer();
  ^^^^^^^^^^^

Function names are case-sensitive and must match exactly, just like variable names.

4. Defining two functions with the same name

dart
// void greet() {
//   print('Hello!');
// }
//
// void greet() { // ✗
//   print('Hi!');
// }
output
Error: 'greet' is already declared in this scope.
void greet() {
     ^^^^^

Every top-level function needs its own name.

5. Using a void call as a value

dart
// print(printHeader()); // ✗ printHeader is void
output
Error: This expression has type 'void' and can't be used.

A void function does a job; it does not produce a value (section 5).

6. Using another function's local variable

A variable declared inside one function is invisible to the others (section 10). Put shared data in a top-level variable — or, from Lecture 031, pass it as a parameter.


Best Practices

  • Name functions with a verb in lowerCamelCase: printHeader, addBonus, payRent.
  • Give each function one job. If the name needs "and", consider two functions.
  • When you are about to copy-paste lines, make a function instead.
  • Keep main() short — a list of calls that reads like a summary of the program.
  • Use top-level variables sparingly; Lecture 031 shows a cleaner way to share data.

Mini Challenge

Write a program for Zayan's birthday card with three functions — printBorder(), printMessage(), and printCard() — where printCard() calls the other two, and main() only calls printCard().

Your program should print exactly:

output
************
Happy Birthday, Zayan!
************

Try it yourself before opening the solution.

Show solution
dart
void main() {
  printCard();
}

void printCard() {
  printBorder();
  printMessage();
  printBorder();
}

void printBorder() {
  print('************');
}

void printMessage() {
  print('Happy Birthday, Zayan!');
}
output
************
Happy Birthday, Zayan!
************

How it works

  1. Dart calls main(), which calls printCard().
  2. printCard() calls printBorder() twice and printMessage() once, in order.
  3. The border is defined once but used twice.

Practice Questions

Work through these in order — they run from beginner to application to challenge. Every question gives you exact values, so you can compare your output with the answers.

Beginner

  1. Write a function sayHello() that prints Hello, Sara!, and call it from main().

  2. Write a function printStars() that prints *****. Call it three times.

  3. What does this program print? Work it out before running it.

    dart
    void b() {
      print('B');
    }
    
    void main() {
      print('A');
      b();
      print('C');
      b();
    }

Application

  1. Write showMenu() that prints three lines: 1. Tea, 2. Coffee, 3. Juice. Call it once, with print('--- Menu ---'); before the call in main().
  2. Define printFooter() below main() that prints Goodbye!, and call it from main().
  3. Create a top-level int count = 0; and a function increment() that adds 1 to it. Call increment() four times, then print Count: 4.
  4. Create a top-level double balance = 500;, a function deposit100() that adds 100, and a function printBalance(). Call printBalance(), deposit100(), printBalance().
  5. Write printTemperature() that stores a local double celsius = 30; and prints 30.0°C = 86.0°F, calculating Fahrenheit inside the function.

Challenge

  1. Write a printReport() function that calls three others — printName() (Name: Ali), printMarks() (Marks: 240), and printGrade() (Grade: A) — and call only printReport() from main().
  2. A shop starts with a top-level int stock = 10;. Write sellOne() (subtracts 1) and restock() (adds 5). In main(), use a for loop to call sellOne() 3 times, then call restock() once, then print Stock: 12.

Practice Answers

Question 1 — Solution

dart
void sayHello() {
  print('Hello, Sara!');
}

void main() {
  sayHello();
}
output
Hello, Sara!

Question 2 — Solution

dart
void printStars() {
  print('*****');
}

void main() {
  printStars();
  printStars();
  printStars();
}
output
*****
*****
*****

Question 3 — Solution

output
A
B
C
B

Each b(); jumps into b, prints B, and comes back to the next line of main().

Question 4 — Solution

dart
void showMenu() {
  print('1. Tea');
  print('2. Coffee');
  print('3. Juice');
}

void main() {
  print('--- Menu ---');
  showMenu();
}
output
--- Menu ---
1. Tea
2. Coffee
3. Juice

Question 5 — Solution

dart
void main() {
  printFooter();
}

void printFooter() {
  print('Goodbye!');
}
output
Goodbye!

Question 6 — Solution

dart
int count = 0;

void increment() {
  count++;
}

void main() {
  increment();
  increment();
  increment();
  increment();
  print('Count: $count');
}
output
Count: 4

Question 7 — Solution

dart
double balance = 500;

void deposit100() {
  balance += 100;
}

void printBalance() {
  print('Balance: $balance');
}

void main() {
  printBalance();
  deposit100();
  printBalance();
}
output
Balance: 500.0
Balance: 600.0

Question 8 — Solution

dart
void printTemperature() {
  double celsius = 30;
  double fahrenheit = celsius * 9 / 5 + 32;
  print('$celsius°C = $fahrenheit°F');
}

void main() {
  printTemperature();
}
output
30.0°C = 86.0°F

Question 9 — Solution

dart
void main() {
  printReport();
}

void printReport() {
  printName();
  printMarks();
  printGrade();
}

void printName() {
  print('Name: Ali');
}

void printMarks() {
  print('Marks: 240');
}

void printGrade() {
  print('Grade: A');
}
output
Name: Ali
Marks: 240
Grade: A

Question 10 — Solution

dart
int stock = 10;

void sellOne() {
  stock--;
}

void restock() {
  stock += 5;
}

void main() {
  for (var i = 0; i < 3; i++) {
    sellOne();
  }
  restock();
  print('Stock: $stock');
}
output
Stock: 12

10 - 3 = 7, then 7 + 5 = 12. The loop decides how many times; the function decides what happens each time.


Quick Revision

  1. What is a function?
  2. What is the difference between defining and calling a function?
  3. What does void mean?
  4. Who calls main()?
  5. What do the empty () after a function's name mean?
  6. Does it matter whether a function is defined above or below main()?
  7. After a called function finishes, where does the program continue?
  8. Why can't main() use a variable declared inside another function?

Key Takeaways

  • A function is a named block of code; you define it once and call it many times.
  • A definition has a return type (void), a name, a parameter list (), and a body { }.
  • Defining does nothing by itself — the body runs only when the function is called.
  • void means the function gives nothing back, so its call cannot be used as a value.
  • main() is an ordinary function that Dart calls for you when the program starts.
  • Top-level functions can be defined in any order; the order of the calls is what counts.
  • Functions can call other functions; each call returns to the spot it came from.
  • Local variables belong to their function; top-level variables are shared by all functions.

What's Next?

Lecture 031 — Parameters & Return Values. Our functions can only do the same thing every time: greet() always greets Ali, and sharing data means top-level variables. Next we fill the empty () with parameters, so the caller can hand a function its inputs, and use return so a function can hand a result back.


Video lecture

Subscribe
Placeholder video — the real recording isn't linked yet.