Watch the video (11 min)
On this page26 sections
  1. Prerequisites
  2. Connection With Previous Lectures
  3. Learning Objectives
  4. 1. What Is a Parameter?
  5. 2. Parameters and Arguments
  6. 3. More Than One Parameter
  7. 4. Dart Checks Every Argument
  8. 5. Returning a Value
  9. 6. Using a Returned Value
  10. 7. return Ends the Function
  11. 8. Returning Early
  12. 9. Every Path Must Return
  13. 10. void Means "Returns Nothing"
  14. 11. Don't Leave Out the Return Type
  15. 12. Nullable Return Types
  16. 13. late Can Delay a Calculation
  17. 14. A Real-World Example
  18. Code Examples
  19. Common Beginner Mistakes
  20. Best Practices
  21. Mini Challenge
  22. Practice Questions
  23. Practice Answers
  24. Quick Revision
  25. Key Takeaways
  26. What's Next?

Lecture 31 — Parameters & Return Values

Category6 — Functions
Lecture031 of 140
Estimated video length11 min
TargetDart 3.12.2
LevelBeginner

A function that does the same thing every time is only half useful. Parameters let you hand a function new values on each call, and return values let it hand a result back.

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 001–030:

  • variables, types, string interpolation, and late (Lecture 006)
  • nullable types (int?) and the ?? operator
  • if and if-else statements
  • defining a void function with no parameters and calling it from main()

Connection With Previous Lectures

In Lecture 030 we wrote functions like this:

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

It works, but it can only ever greet Ali. To greet Sara we would need a second function, and a third for Zayan — the same code copied three times. And a void function that calculates a total can only print it: the rest of the program never gets the number back. Lecture 030 gave a short preview of the fix — String storeName() with the keyword return. This lecture explains it properly, and fills the empty () too.


Learning Objectives

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

  • Define functions that take one or more typed parameters
  • Explain the difference between a parameter and an argument
  • Declare a return type and send a value back with return
  • Store, print, and calculate with the value a function returns
  • Use return to leave a function early
  • Recognize why every path of a non-void function must return a value
  • Explain why a missing return type is a problem
  • Write functions with nullable return types for results that may be missing

1. What Is a Parameter?

A parameter is a variable that a function receives from whoever calls it. You write it inside the parentheses, with a type and a name.

Analogy — think of a form with a blank line: "Hello, ______!". The function is the form, the parameter is the blank, and each call fills the blank with a different name.

dart
void greet(String name) {
  print('Hello, $name!');
}

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

One function now greets anyone.


2. Parameters and Arguments

The two words are easy to mix up:

  • A parameter is the name in the function's definition — name above.
  • An argument is the actual value you pass when calling it — 'Ali' and 'Sara'.
dart
void showAge(int age) {
  // age is the parameter
  print('Age: $age');
}

void main() {
  showAge(20); // 20 is the argument
}
output
Age: 20

When the function runs, the parameter behaves like a local variable that already holds the argument's value.


3. More Than One Parameter

Separate parameters with commas. Arguments are matched by position: the first argument goes to the first parameter, the second to the second.

dart
void showStudent(String name, int marks) {
  print('$name scored $marks');
}

void main() {
  showStudent('Zayan', 92);
}
output
Zayan scored 92

Swapping the arguments to showStudent(92, 'Zayan') would not compile — 92 is not a String. Optional and named parameters, which loosen these rules, arrive in Lectures 032 and 033.


4. Dart Checks Every Argument

Each parameter has a type, so Dart checks each argument before the program runs:

dart
void greet(String name) {
  print('Hello, $name!');
}

void main() {
  greet(25); // ✗
}
output
Error: The argument type 'int' can't be assigned to the parameter type 'String'.
  greet(25); // ✗
        ^

The number of arguments is checked too. Every parameter in this lecture is required:

dart
void showStudent(String name, int marks) {
  print('$name scored $marks');
}

void main() {
  showStudent('Ali'); // ✗ marks is missing
}
output
Error: Too few positional arguments: 2 required, 1 given.
  showStudent('Ali'); // ✗ marks is missing
             ^

5. Returning a Value

So far our functions only print. To send a result back to the caller, replace void with the type of the result — the return type — and use the return keyword.

dart
int add(int a, int b) {
  return a + b;
}

void main() {
  int total = add(5, 3);
  print(total);
}
output
8

Read int add(...) as "a function named add that gives back an int". The call add(5, 3) is replaced by the value it returns, 8, which is stored in total. This is exactly how the storeName() preview in Lecture 030 worked — it returned a String.


6. Using a Returned Value

A function call that returns a value can go anywhere a value of that type can go:

dart
int add(int a, int b) {
  return a + b;
}

void main() {
  int total = add(10, 20); // store it
  print(add(1, 2)); // print it directly
  print('Total: ${add(4, 4)}'); // inside a string
  print(add(10, 20) * 2); // in a calculation
  print(add(add(1, 2), 3)); // as an argument
  print(total);
}
output
3
Total: 8
60
6
30

In the last line before print(total), the inner add(1, 2) runs first and its result, 3, becomes the first argument of the outer call. Notice also the ${...} form of interpolation: a function call needs the braces.


7. return Ends the Function

return does two things: it hands back the value and stops the function immediately. Any line after it never runs.

dart
int square(int n) {
  return n * n;
  print('Done'); // never runs
}

void main() {
  print(square(4));
}
output
16

'Done' is never printed. dart analyze marks that line as unreachable:

output
warning - Dead code. Try removing the code, or fixing the code before it so that it can be reached. - dead_code

8. Returning Early

Because return stops the function, you can use it inside an if to finish as soon as the answer is known. This is called an early return.

dart
String result(int marks) {
  if (marks >= 50) {
    return 'Pass';
  }
  return 'Fail';
}

void main() {
  print(result(72));
  print(result(35));
}
output
Pass
Fail

For 72, the first return runs and the function ends. For 35, the if is skipped and the second return runs. No else is needed.

A void function can return early too — write return; with no value:

dart
void withdraw(int balance, int amount) {
  if (amount > balance) {
    print('Not enough money');
    return;
  }
  print('New balance: ${balance - amount}');
}

void main() {
  withdraw(1000, 300);
  withdraw(1000, 5000);
}
output
New balance: 700
Not enough money

9. Every Path Must Return

If a function promises an int, it must return an int on every path through its body. Forget one, and Dart refuses to compile:

dart
int bonus(int marks) {
  if (marks >= 90) {
    return 10;
  }
  // ✗ nothing is returned when marks is below 90
}

void main() {
  print(bonus(95));
}
output
Error: A non-null value must be returned since the return type 'int' doesn't allow null.
int bonus(int marks) {
    ^

A function that reaches its closing } without return gives back null — and int does not allow null. Add a final return 0; and the error is gone.


10. void Means "Returns Nothing"

A void function cannot return a value:

dart
void greet(String name) {
  return 'Hello, $name!'; // ✗
}

void main() {
  greet('Ali');
}
output
Error: Can't return a value from a void function.
  return 'Hello, $name!'; // ✗
                        ^

And you cannot use the "result" of a void function, because there is none:

dart
void greet(String name) {
  print('Hello, $name!');
}

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

If you want the text back, the function must return String instead of printing it.


11. Don't Leave Out the Return Type

Dart lets you write a function without a return type, but it does not infer one for you. The result is quietly dynamic — and in Lecture 011 we saw that dynamic turns type checking off.

dart
add(int a, int b) {
  return a + b;
}

void main() {
  var total = add(2, 3);
  print(total.length); // an int has no length
}

This compiles, then crashes while running:

output
Unhandled exception:
NoSuchMethodError: Class 'int' has no instance getter 'length'.
Receiver: 5
Tried calling: length

dart analyze warns about the missing type before you run anything:

output
info - Missing type annotation. Try adding a type annotation. - strict_top_level_inference

Writing int add(int a, int b) turns that crash into a compile-time error. The same goes for parameters: always give them a type.


12. Nullable Return Types

Sometimes a function honestly may not have an answer. Make the return type nullable with ? and return null when there is nothing to give back — just like int.tryParse, which we met in Lecture 013.

dart
int? findMark(String name) {
  if (name == 'Ali') {
    return 80;
  }
  if (name == 'Sara') {
    return 95;
  }
  return null;
}

void main() {
  print(findMark('Sara'));
  print(findMark('Zayan'));
  int mark = findMark('Zayan') ?? 0;
  print(mark);
}
output
95
null
0

The caller gets an int?, so it must deal with the missing case — here with ??. Trying to store it straight into an int fails:

dart
int? findMark(String name) {
  if (name == 'Ali') {
    return 80;
  }
  return null;
}

void main() {
  int mark = findMark('Sara'); // ✗
  print(mark);
}
output
Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
  int mark = findMark('Sara'); // ✗
             ^

13. late Can Delay a Calculation

Lecture 006 promised one more use of late. When a late variable is given a value from a function call, the call does not run at the declaration. It runs the first time the variable is read — and only once.

dart
int loadBalance() {
  print('Loading balance...');
  return 1000;
}

void main() {
  late final int balance = loadBalance();
  print('Program started');
  print('Balance: $balance');
  print('Again: $balance');
}
output
Program started
Loading balance...
Balance: 1000
Again: 1000

'Loading balance...' appears after 'Program started', and only once. Remove late and the order flips: loadBalance() runs right away on the declaration line, before 'Program started'. This is useful for slow calculations that might not be needed at all.


14. A Real-World Example

dart
double subtotal(double price, int quantity) {
  return price * quantity;
}

double discount(double amount) {
  if (amount < 1000) {
    return 0;
  }
  return amount * 0.10;
}

void printReceipt(String customer, double price, int quantity) {
  double sub = subtotal(price, quantity);
  double off = discount(sub);
  print('Customer: $customer');
  print('Subtotal: $sub');
  print('Discount: $off');
  print('Total: ${sub - off}');
}

void main() {
  printReceipt('Sara', 450, 3);
}
output
Customer: Sara
Subtotal: 1350.0
Discount: 135.0
Total: 1215.0

Each function has one job. subtotal and discount calculate and return; printReceipt takes parameters, combines the returned values, and prints. Small functions that return values can be combined like building blocks.


Code Examples

Example 1 — One Parameter

dart
void welcome(String name) {
  print('Welcome, $name!');
}

void main() {
  welcome('Ali');
  welcome('Zayan');
}
output
Welcome, Ali!
Welcome, Zayan!

Example 2 — Two Parameters

dart
void showPrice(String product, double price) {
  print('$product costs $price');
}

void main() {
  showPrice('Notebook', 250);
  showPrice('Pen', 40.5);
}
output
Notebook costs 250.0
Pen costs 40.5

Example 3 — Returning an int

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

void main() {
  int result = multiply(6, 7);
  print(result);
}
output
42

Example 4 — Returning a bool

dart
bool isAdult(int age) {
  return age >= 18;
}

void main() {
  print(isAdult(20));
  print(isAdult(6));
}
output
true
false

age >= 18 is already a bool, so the function returns it directly — no if needed.

Example 5 — Returning a String

dart
String fullName(String first, String last) {
  return '$first $last';
}

void main() {
  String name = fullName('Sara', 'Khan');
  print('Hello, $name');
}
output
Hello, Sara Khan

Example 6 — Early Return

dart
String sign(int n) {
  if (n > 0) {
    return 'positive';
  }
  if (n < 0) {
    return 'negative';
  }
  return 'zero';
}

void main() {
  print(sign(5));
  print(sign(-3));
  print(sign(0));
}
output
positive
negative
zero

Example 7 — Student Marks

dart
int total(int math, int science, int english) {
  return math + science + english;
}

double average(int sum, int subjects) {
  return sum / subjects;
}

void main() {
  int sum = total(80, 75, 85);
  print('Total: $sum');
  print('Average: ${average(sum, 3)}');
}
output
Total: 240
Average: 80.0

How it works

  1. total adds three marks and returns 240.
  2. That returned value is stored in sum and passed on to average.
  3. / always produces a double, so average returns 80.0.

Example 8 — Shopping Total

dart
double lineTotal(double price, int quantity) {
  return price * quantity;
}

void main() {
  double notebooks = lineTotal(250, 3);
  double pens = lineTotal(40, 5);
  print('Notebooks: $notebooks');
  print('Pens: $pens');
  print('Grand total: ${notebooks + pens}');
}
output
Notebooks: 750.0
Pens: 200.0
Grand total: 950.0

How it works

  1. One function calculates any line of the bill.
  2. Each call returns a double, stored in its own variable.
  3. The grand total is simply the two returned values added together.

Example 9 — Bank Balance

dart
int withdraw(int balance, int amount) {
  if (amount > balance) {
    print('Declined: only $balance available');
    return balance;
  }
  return balance - amount;
}

void main() {
  int balance = 1000;
  balance = withdraw(balance, 300);
  print('Balance: $balance');
  balance = withdraw(balance, 900);
  print('Balance: $balance');
}
output
Balance: 700
Declined: only 700 available
Balance: 700

How it works

  1. withdraw returns the new balance, and main stores it back into balance.
  2. When the amount is too large, the early return gives back the unchanged balance.
  3. The function never changes main's variable itself — main decides to store the result.

Example 10 — Temperature Conversion

dart
double toFahrenheit(double celsius) {
  return celsius * 9 / 5 + 32;
}

String describe(double celsius) {
  if (celsius >= 30) {
    return 'hot';
  }
  if (celsius >= 15) {
    return 'mild';
  }
  return 'cold';
}

void main() {
  double today = 34;
  print('$today°C is ${toFahrenheit(today)}°F, which is ${describe(today)}');
}
output
34.0°C is 93.2°F, which is hot

Both returned values sit directly inside the string with ${...}.


Common Beginner Mistakes

1. Passing arguments in the wrong order

dart
// void showStudent(String name, int marks) { ... }
// showStudent(92, 'Zayan');
output
Error: The argument type 'int' can't be assigned to the parameter type 'String'.

Positional arguments must follow the order of the parameters.

2. Passing the wrong number of arguments

dart
// int add(int a, int b) { ... }
// add(5, 3, 2);
output
Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.

3. Calculating a value but forgetting return

dart
// int add(int a, int b) {
//   a + b;
// }
output
Error: A non-null value must be returned since the return type 'int' doesn't allow null.

a + b computes the sum and throws it away. Write return a + b;.

4. Printing instead of returning

A function that prints its result cannot be used in a calculation. If the caller needs the value, return it and let the caller print it.

5. Storing the result in the wrong type

dart
// int add(int a, int b) { ... }
// String total = add(2, 3);
output
Error: A value of type 'int' can't be assigned to a variable of type 'String'.

6. Leaving out the return type

The return type becomes dynamic, and mistakes slip through to run time. Always write it.


Best Practices

  • Always write the return type and the type of every parameter.
  • Name functions with verbs or questions: calculateTotal, isAdult, findMark.
  • Prefer functions that return values over functions that print them; print in one place.
  • Use early returns to handle special cases first, keeping the main path unindented.
  • Use a nullable return type only when "no result" is a real possibility.
  • Keep each function to one job, and keep its parameter list short.

Mini Challenge

Write a function grade that takes an int mark and returns a String: 'A' for 80 or more, 'B' for 60 or more, and 'C' otherwise. Use early returns. Call it for Ali (85), Sara (64), and Zayan (40).

Your program should print exactly:

output
Ali: A
Sara: B
Zayan: C

Try it yourself before opening the solution.

Show solution
dart
String grade(int marks) {
  if (marks >= 80) {
    return 'A';
  }
  if (marks >= 60) {
    return 'B';
  }
  return 'C';
}

void main() {
  print('Ali: ${grade(85)}');
  print('Sara: ${grade(64)}');
  print('Zayan: ${grade(40)}');
}
output
Ali: A
Sara: B
Zayan: C

How it works

  1. Each if returns as soon as a grade matches, ending the function.
  2. The final return 'C'; covers every remaining mark, so every path returns.
  3. The calls sit inside the strings with ${...}.

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 sayGoodbye that takes a String name and prints Goodbye, <name>!. Call it with 'Zayan'.
  2. Write a function half that takes a double and returns half of it as a double. Print half(9).
  3. Write a function isEven that takes an int and returns a bool. Print isEven(10) and isEven(7).

Application

  1. Write int rectangleArea(int width, int height). Print the area for width = 12 and height = 5.
  2. Write int subtract(int a, int b). Store subtract(100, 35) in a variable and print Result: 65.
  3. Write String initials(String first, String last) that returns the first letter of each name joined together (use first[0]). Print initials('Ali', 'Raza').
  4. Write int maxOf(int a, int b) using an early return. Print maxOf(8, 3) and maxOf(4, 9).
  5. Write double priceWithTax(double price) that adds 5% tax. Print priceWithTax(200).

Challenge

  1. Write int? safeDivide(int a, int b) that returns null when b is 0, otherwise a ~/ b. Print safeDivide(20, 4), then print safeDivide(5, 0) ?? -1.
  2. Write int deposit(int balance, int amount) and int withdraw(int balance, int amount) (decline with an early return if the amount is too large). Starting from 500, deposit 200, withdraw 1000, then withdraw 300, printing the balance after each step as Balance: ….

Practice Answers

Question 1 — Solution

dart
void sayGoodbye(String name) {
  print('Goodbye, $name!');
}

void main() {
  sayGoodbye('Zayan');
}
output
Goodbye, Zayan!

Question 2 — Solution

dart
double half(double n) {
  return n / 2;
}

void main() {
  print(half(9));
}
output
4.5

The argument 9 is accepted for a double parameter and becomes 9.0.

Question 3 — Solution

dart
bool isEven(int n) {
  return n % 2 == 0;
}

void main() {
  print(isEven(10));
  print(isEven(7));
}
output
true
false

Question 4 — Solution

dart
int rectangleArea(int width, int height) {
  return width * height;
}

void main() {
  print(rectangleArea(12, 5));
}
output
60

Question 5 — Solution

dart
int subtract(int a, int b) {
  return a - b;
}

void main() {
  int result = subtract(100, 35);
  print('Result: $result');
}
output
Result: 65

Question 6 — Solution

dart
String initials(String first, String last) {
  return '${first[0]}${last[0]}';
}

void main() {
  print(initials('Ali', 'Raza'));
}
output
AR

Question 7 — Solution

dart
int maxOf(int a, int b) {
  if (a > b) {
    return a;
  }
  return b;
}

void main() {
  print(maxOf(8, 3));
  print(maxOf(4, 9));
}
output
8
9

Question 8 — Solution

dart
double priceWithTax(double price) {
  return price * 1.05;
}

void main() {
  print(priceWithTax(200));
}
output
210.0

Question 9 — Solution

dart
int? safeDivide(int a, int b) {
  if (b == 0) {
    return null;
  }
  return a ~/ b;
}

void main() {
  print(safeDivide(20, 4));
  print(safeDivide(5, 0) ?? -1);
}
output
5
-1

Dividing by zero has no sensible answer, so the function says so with null, and the caller picks a fallback with ??.

Question 10 — Solution

dart
int deposit(int balance, int amount) {
  return balance + amount;
}

int withdraw(int balance, int amount) {
  if (amount > balance) {
    print('Declined');
    return balance;
  }
  return balance - amount;
}

void main() {
  int balance = 500;
  balance = deposit(balance, 200);
  print('Balance: $balance');
  balance = withdraw(balance, 1000);
  print('Balance: $balance');
  balance = withdraw(balance, 300);
  print('Balance: $balance');
}
output
Balance: 700
Declined
Balance: 700
Balance: 400

Quick Revision

  1. What is the difference between a parameter and an argument?
  2. How does Dart match arguments to parameters in this lecture?
  3. What two things does return do?
  4. What does void mean as a return type?
  5. Why must a function with return type int return on every path?
  6. What return type does a function get if you leave the return type out?
  7. When should a function have a nullable return type like int??
  8. When does late final x = compute(); call compute()?
  9. Why do you need ${...} to put a function call inside a string?

Key Takeaways

  • A parameter is a typed variable in the function definition; an argument is the value passed in a call.
  • Arguments are matched to parameters by position, and Dart checks both their types and their number.
  • The return type before the name says what the function gives back; void means nothing.
  • return hands back a value and ends the function immediately.
  • A returned value can be stored, printed, interpolated, calculated with, or passed to another function.
  • Early returns handle special cases first; a void function uses a bare return;.
  • A non-void, non-nullable function must return a value on every path.
  • Leaving out the return type makes it dynamic — always write it.
  • A nullable return type (int?) tells the caller "there may be no answer".
  • late with a function call delays that call until the variable is first read.

What's Next?

Lecture 032 — Positional Parameters. Every parameter in this lecture was required: miss one and the program does not compile. But some values are genuinely optional — a greeting that is usually 'Hello', a discount that is usually zero. Next we look closer at positional parameters and learn how to make some of them optional, with default values.


Video lecture

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