Watch the video (9 min)
On this page23 sections
  1. Prerequisites
  2. Connection With Previous Lectures
  3. Learning Objectives
  4. 1. Required Positional Parameters: A Recap
  5. 2. Making a Parameter Optional with [ ]
  6. 3. You Have Already Used One
  7. 4. An Optional Parameter Needs a Default
  8. 5. Nullable Optional Parameters
  9. 6. Several Optional Parameters
  10. 7. Passing null Does Not Skip a Parameter
  11. 8. Order Rule: Required First, Optional Last
  12. 9. The Number of Arguments Is Still Checked
  13. 10. Default Values Must Be Constant
  14. 11. A Real-World Example
  15. Code Examples
  16. Common Beginner Mistakes
  17. Best Practices
  18. Mini Challenge
  19. Practice Questions
  20. Practice Answers
  21. Quick Revision
  22. Key Takeaways
  23. What's Next?

Lecture 32 — Positional Parameters

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

Until now every parameter was required: miss one and the program does not compile. Optional positional parameters let the caller leave a value out, and a default value fills the gap.

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–031:

  • nullable types (String?), the ?? operator, and const (Lectures 006 and 013–014)
  • the string method substring (Lecture 008)
  • if statements
  • functions with typed parameters and return values (Lecture 031)

Connection With Previous Lectures

In Lecture 031 we wrote a greeting function:

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

Almost every call uses 'Hello', yet the caller must type it every single time — greet('Ali', 'Hello'), greet('Sara', 'Hello'). Leave it out and Dart stops with Too few positional arguments. We need a way to say: "this value is usually 'Hello'; only pass it when you want something different."


Learning Objectives

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

  • Explain what makes a parameter positional and required
  • Make parameters optional with square brackets [ ]
  • Give an optional parameter a default value
  • Use a nullable optional parameter and handle the null case
  • Pass some optional arguments and leave out the rest
  • Follow the order rules: required parameters first, optional ones last
  • Recognize the errors Dart gives when these rules are broken

1. Required Positional Parameters: A Recap

Every parameter we have written so far is positional — arguments are matched by their position — and required — each one must be passed.

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

void main() {
  showStudent('Sara', 95);
}
output
Sara scored 95

The first argument goes to name, the second to marks. Pass only one, and Dart refuses:

output
Error: Too few positional arguments: 2 required, 1 given.

2. Making a Parameter Optional with [ ]

Wrap a parameter in square brackets to make it optional, and give it a value with =. That value is its default value: the one it gets when the caller leaves it out.

Analogy — ordering tea at a café. If you just say "tea", you get a regular cup; you only mention the size when you want something different. The size is optional, and "regular" is its default.

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

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

name is still required. greeting is optional: the first call leaves it out and gets 'Hello'; the second passes 'Good morning', which replaces the default.


3. You Have Already Used One

In Lecture 008, substring worked with one argument or two. Its second parameter is an optional positional parameter:

dart
void main() {
  String word = 'Notebook';
  print(word.substring(0, 4));
  print(word.substring(4));
}
output
Note
book

Without the second argument, substring goes to the end of the string. Now you can write functions that behave the same way.


4. An Optional Parameter Needs a Default

What if we leave out the default?

dart
void greet(String name, [String greeting]) {
  print('$greeting, $name!');
}

void main() {
  greet('Ali');
}
output
Error: The parameter 'greeting' can't have a value of 'null' because of its type 'String', but the implicit default value is 'null'.
Try adding either an explicit non-'null' default value or the 'required' modifier.

When an optional argument is left out, the parameter needs some value. With no default written, Dart would use null — and String does not allow null. You have two fixes: give it a default (Step 2), or make its type nullable (Step 5). The required modifier the message mentions belongs to named parameters, in Lecture 033.


5. Nullable Optional Parameters

Sometimes there is no sensible default — a person may simply have no title. Make the type nullable, and the implicit default is null:

dart
void showName(String name, [String? title]) {
  if (title == null) {
    print(name);
  } else {
    print('$title $name');
  }
}

void main() {
  showName('Ali');
  showName('Sara', 'Dr.');
}
output
Ali
Dr. Sara

Inside the function, title is a String?, so Dart makes you handle the null case before using it — just like any other nullable variable from Lecture 013. The ?? operator is often the shortest way:

dart
void showCity(String name, [String? city]) {
  print('$name lives in ${city ?? 'an unknown city'}');
}

void main() {
  showCity('Zayan', 'Lahore');
  showCity('Ali');
}
output
Zayan lives in Lahore
Ali lives in an unknown city

6. Several Optional Parameters

All optional parameters go inside one pair of brackets, separated by commas:

dart
void order(String item, [int quantity = 1, double price = 50]) {
  print('$quantity x $item = ${quantity * price}');
}

void main() {
  order('Pen');
  order('Notebook', 3);
  order('Bag', 2, 1200);
}
output
1 x Pen = 50.0
3 x Notebook = 150.0
2 x Bag = 2400.0

Optional arguments are still matched by position, filled from left to right. So you can pass the quantity alone, but you cannot pass the price without also passing the quantity — there is no way to skip a position.


7. Passing null Does Not Skip a Parameter

A common idea is to pass null to "use the default". It does not work: a parameter of type String never accepts null, even an optional one.

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

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

The default is used only when the argument is left out. To use it, simply stop before that position: greet('Ali').


8. Order Rule: Required First, Optional Last

Required parameters always come first, and the bracket group must be the last thing in the parameter list. Putting a required parameter after it is a syntax error:

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

void main() {
  greet('Hi', 'Ali');
}
output
Error: Expected ')' before this.
void greet([String greeting = 'Hello'], String name) {
                                      ^

Dart expects the list to end right after ] (the follow-on errors it also prints vanish with this one). The rule makes sense: if an optional parameter came first, Dart could not tell whether your first argument was meant for it or for the required one. Put String name first and the error is gone.


9. The Number of Arguments Is Still Checked

Optional parameters widen the range, but there is still a minimum and a maximum. With one required and one optional parameter, a call needs one or two arguments:

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

void main() {
  greet('Ali', 'Hi', 'Sara'); // ✗
}
output
Error: Too many positional arguments: 2 allowed, but 3 found.
Try removing the extra positional arguments.

Calling greet() with nothing fails too: Too few positional arguments: 1 required, 0 given.


10. Default Values Must Be Constant

A default value is fixed when the program is compiled, so it must be a constant: a literal like 'Hello' or 0.05, or a const variable. An ordinary variable is rejected:

dart
double rate = 0.05;

double addTax(double price, [double tax = rate]) {
  return price + price * tax;
}

void main() {
  print(addTax(100));
}
output
Error: Not a constant expression.
double addTax(double price, [double tax = rate]) {
                                          ^^^^

Change the first line to const double rate = 0.05; and it compiles, printing 105.0.


11. A Real-World Example

dart
const double standardTax = 0.05;

double finalPrice(
  double price, [
  int quantity = 1,
  double tax = standardTax,
  double? discount,
]) {
  double subtotal = price * quantity;
  double afterDiscount = subtotal - (discount ?? 0);
  return afterDiscount + afterDiscount * tax;
}

void main() {
  print(finalPrice(200));
  print(finalPrice(200, 3));
  print(finalPrice(200, 3, 0.10));
  print(finalPrice(200, 3, 0.10, 100));
}
output
210.0
630.0
660.0
550.0

price is required. quantity and tax have defaults, the tax coming from a const variable. discount has no sensible default, so it is nullable and handled with ??. Each call passes one more argument, always from left to right. When the list grows this long, dart format puts one parameter on each line, as shown.


Code Examples

Example 1 — Required Positional Parameters

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

void main() {
  print(add(7, 5));
}
output
12

Example 2 — One Optional Parameter with a Default

dart
void welcome(String name, [String place = 'Dart class']) {
  print('Welcome to $place, $name!');
}

void main() {
  welcome('Zayan');
  welcome('Sara', 'the library');
}
output
Welcome to Dart class, Zayan!
Welcome to the library, Sara!

Example 3 — A Default Number

dart
int power(int base, [int exponent = 2]) {
  int result = 1;
  for (int i = 0; i < exponent; i++) {
    result *= base;
  }
  return result;
}

void main() {
  print(power(5));
  print(power(2, 10));
}
output
25
1024

Example 4 — A Nullable Optional Parameter

dart
void showPhone(String name, [String? phone]) {
  print('$name: ${phone ?? 'no phone'}');
}

void main() {
  showPhone('Ali', '0300-1234567');
  showPhone('Sara');
}
output
Ali: 0300-1234567
Sara: no phone

Example 5 — Two Optional Parameters

dart
void line(String text, [int times = 1, String separator = ' ']) {
  String result = text;
  for (int i = 1; i < times; i++) {
    result = '$result$separator$text';
  }
  print(result);
}

void main() {
  line('Hi');
  line('Hi', 3);
  line('Hi', 3, '-');
}
output
Hi
Hi Hi Hi
Hi-Hi-Hi

Example 6 — A Default from a const Variable

dart
const String defaultCurrency = 'PKR';

String formatPrice(double amount, [String currency = defaultCurrency]) {
  return '$amount $currency';
}

void main() {
  print(formatPrice(499));
  print(formatPrice(20, 'USD'));
}
output
499.0 PKR
20.0 USD

Example 7 — Student Marks

dart
String result(String name, int marks, [int passMark = 50]) {
  if (marks >= passMark) {
    return '$name passed';
  }
  return '$name failed';
}

void main() {
  print(result('Ali', 55));
  print(result('Sara', 55, 60));
}
output
Ali passed
Sara failed

How it works

  1. Most subjects use the usual pass mark, so passMark defaults to 50.
  2. A harder subject passes 60, and the same 55 now fails.

Example 8 — Shopping Total

dart
double total(double price, [int quantity = 1, double delivery = 150]) {
  return price * quantity + delivery;
}

void main() {
  print('Book: ${total(800)}');
  print('Pens: ${total(40, 10)}');
  print('Pickup: ${total(800, 1, 0)}');
}
output
Book: 950.0
Pens: 550.0
Pickup: 800.0

How it works

  1. To change delivery, the caller must also pass quantity — even when it is the default 1. Positions cannot be skipped.

Example 9 — Bank Balance

dart
int withdraw(int balance, int amount, [int fee = 0]) {
  int cost = amount + fee;
  if (cost > balance) {
    print('Declined');
    return balance;
  }
  return balance - cost;
}

void main() {
  int balance = 1000;
  balance = withdraw(balance, 300);
  print('Balance: $balance');
  balance = withdraw(balance, 200, 25);
  print('Balance: $balance');
}
output
Balance: 700
Balance: 475

How it works

  1. A normal withdrawal is free, so fee defaults to 0.
  2. An ATM withdrawal passes a fee of 25, which is added to the cost.

Example 10 — Temperature Conversion

dart
double convert(double value, [String to = 'F']) {
  if (to == 'C') {
    return (value - 32) * 5 / 9;
  }
  return value * 9 / 5 + 32;
}

void main() {
  print(convert(30));
  print(convert(212, 'C'));
}
output
86.0
100.0

Converting Celsius to Fahrenheit is the common case, so it is the default.


Common Beginner Mistakes

1. An optional non-nullable parameter with no default

dart
// void greet(String name, [String greeting]) { ... }
output
Error: The parameter 'greeting' can't have a value of 'null' because of its type 'String', but the implicit default value is 'null'.

Give it a default (= 'Hello') or make the type nullable (String?).

2. A required parameter after the optional ones

dart
// void greet([String greeting = 'Hello'], String name) { ... }
output
Error: Expected ')' before this.

The [ ] group must come last.

3. Passing null to use the default

dart
// void greet(String name, [String greeting = 'Hello']) { ... }
// greet('Ali', null);
output
Error: The argument type 'Null' can't be assigned to the parameter type 'String'.

Leave the argument out instead.

4. Trying to skip a position

dart
// void order(String item, [int quantity = 1, double price = 50]) { ... }
// order('Pen', 2.5); // meant as the price
output
Error: The argument type 'double' can't be assigned to the parameter type 'int'.

The second argument always goes to quantity. Write order('Pen', 1, 2.5).

5. Using a nullable parameter without checking it

dart
// void showName(String name, [String? title]) {
//   print(title.length);
// }
output
Error: Property 'length' cannot be accessed on 'String?' because it is potentially null.

Check for null first, or use ??.

6. A non-constant default value

dart
// double rate = 0.05;
// double addTax(double price, [double tax = rate]) { ... }
output
Error: Not a constant expression.

Make the variable const.


Best Practices

  • Make a parameter optional only when most callers would pass the same value.
  • Prefer a default value; use a nullable optional parameter only when there is no sensible default.
  • Put the optional parameter that callers change most often first inside the brackets, so they rarely need to fill in the others.
  • Keep optional positional parameters to one or two. A call like f(200, 3, 0.10, 100) is hard to read — named parameters (Lecture 033) solve this.
  • Use a const variable for a default that appears in several functions.

Mini Challenge

Write a function reportCard that takes a required String name and int marks, plus an optional int total that defaults to 100. It returns a String like 'Ali: 45/50 (90.0%)'. Call it for Ali (45 out of 50), Sara (88), and Zayan (72).

Your program should print exactly:

output
Ali: 45/50 (90.0%)
Sara: 88/100 (88.0%)
Zayan: 72/100 (72.0%)

Try it yourself before opening the solution.

Show solution
dart
String reportCard(String name, int marks, [int total = 100]) {
  double percent = marks / total * 100;
  return '$name: $marks/$total ($percent%)';
}

void main() {
  print(reportCard('Ali', 45, 50));
  print(reportCard('Sara', 88));
  print(reportCard('Zayan', 72));
}
output
Ali: 45/50 (90.0%)
Sara: 88/100 (88.0%)
Zayan: 72/100 (72.0%)

How it works

  1. total sits in brackets with a default of 100, so Sara's and Zayan's calls leave it out.
  2. Ali's test was out of 50, so his call passes it as the third argument.

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 void sayHi(String name, [String punctuation = '!']) that prints Hi, <name><punctuation>. Call it with 'Zayan', then with 'Sara' and '?'.
  2. Write int square(int n) and print square(9). Is n positional, optional, or both?
  3. Write void introduce(String name, [int? age]) that prints I am Ali when no age is given and I am Sara, 21 when it is.

Application

  1. Write double area(double width, [double height = 1]). Print area(5) and area(5, 4).
  2. Write int countdownSum(int from, [int to = 0]) that adds every number from from down to to with a loop. Print countdownSum(4) and countdownSum(10, 8).
  3. Write String repeat(String text, [int times = 2]) that returns text joined to itself times times. Print repeat('ab') and repeat('ab', 3).
  4. Using void order(String item, [int quantity = 1, double price = 50]) from Step 6, write the call that orders 1 'Ruler' at price 30.
  5. Write double deposit(double balance, [double amount = 100]). Starting from 500, deposit the default, then 250, printing the balance each time.

Challenge

  1. Write String temperature(double celsius, [String? city]) that returns '34.0°C in Karachi' when a city is given and '34.0°C' when it is not. Print both.
  2. Write double bill(double price, [int quantity = 1, double? coupon]). The coupon is an amount to subtract. Print bill(300), bill(300, 2), and bill(300, 2, 50).

Practice Answers

Question 1 — Solution

dart
void sayHi(String name, [String punctuation = '!']) {
  print('Hi, $name$punctuation');
}

void main() {
  sayHi('Zayan');
  sayHi('Sara', '?');
}
output
Hi, Zayan!
Hi, Sara?

Question 2 — Solution

dart
int square(int n) {
  return n * n;
}

void main() {
  print(square(9));
}
output
81

n is positional and required — it has no brackets.

Question 3 — Solution

dart
void introduce(String name, [int? age]) {
  if (age == null) {
    print('I am $name');
  } else {
    print('I am $name, $age');
  }
}

void main() {
  introduce('Ali');
  introduce('Sara', 21);
}
output
I am Ali
I am Sara, 21

Question 4 — Solution

dart
double area(double width, [double height = 1]) {
  return width * height;
}

void main() {
  print(area(5));
  print(area(5, 4));
}
output
5.0
20.0

Question 5 — Solution

dart
int countdownSum(int from, [int to = 0]) {
  int sum = 0;
  for (int i = from; i >= to; i--) {
    sum += i;
  }
  return sum;
}

void main() {
  print(countdownSum(4));
  print(countdownSum(10, 8));
}
output
10
27

Question 6 — Solution

dart
String repeat(String text, [int times = 2]) {
  String result = '';
  for (int i = 0; i < times; i++) {
    result += text;
  }
  return result;
}

void main() {
  print(repeat('ab'));
  print(repeat('ab', 3));
}
output
abab
ababab

Question 7 — Solution

dart
void order(String item, [int quantity = 1, double price = 50]) {
  print('$quantity x $item = ${quantity * price}');
}

void main() {
  order('Ruler', 1, 30);
}
output
1 x Ruler = 30.0

The quantity must be written out, even though 1 is its default — otherwise 30 would land in quantity.

Question 8 — Solution

dart
double deposit(double balance, [double amount = 100]) {
  return balance + amount;
}

void main() {
  double balance = 500;
  balance = deposit(balance);
  print('Balance: $balance');
  balance = deposit(balance, 250);
  print('Balance: $balance');
}
output
Balance: 600.0
Balance: 850.0

Question 9 — Solution

dart
String temperature(double celsius, [String? city]) {
  if (city == null) {
    return '$celsius°C';
  }
  return '$celsius°C in $city';
}

void main() {
  print(temperature(34, 'Karachi'));
  print(temperature(34));
}
output
34.0°C in Karachi
34.0°C

Question 10 — Solution

dart
double bill(double price, [int quantity = 1, double? coupon]) {
  return price * quantity - (coupon ?? 0);
}

void main() {
  print(bill(300));
  print(bill(300, 2));
  print(bill(300, 2, 50));
}
output
300.0
600.0
550.0

Quick Revision

  1. What makes a parameter "positional"?
  2. How do you make a positional parameter optional?
  3. When is a default value used?
  4. Why does [String greeting] not compile?
  5. What is the implicit default of a String? optional parameter?
  6. Can you pass the second optional argument without the first?
  7. Where must the [ ] group go in the parameter list?
  8. What kind of value can a default be?

Key Takeaways

  • Positional arguments are matched to parameters by position.
  • Parameters without brackets are required; parameters inside [ ] are optional.
  • A default value (= 'Hello') is used only when the argument is left out.
  • A non-nullable optional parameter must have a default; a nullable one defaults to null.
  • Handle a nullable optional parameter with an if check or ??.
  • Optional arguments fill from left to right — you cannot skip a position, and passing null does not mean "use the default".
  • The [ ] group comes last, after all required parameters.
  • Default values must be constants: literals or const variables.

What's Next?

Lecture 033 — Named Parameters. A call like finalPrice(200, 3, 0.10, 100) works, but what do 0.10 and 100 mean? And to change the last value you must fill in every one before it. Next we learn named parameters, which are passed by name instead of position — in any order, skipping whichever you like — along with the required keyword from Step 4's error message.


Video lecture

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