Question #454EasyDart BasicsImportant

What is the difference between required, optional, and named parameters in Dart?

#dart#functions#parameters#required#named#optional

Answer

Overview

Dart functions support four types of parameters:

  1. Required Positional — Must be provided, order matters
  2. Optional Positional — Can be omitted, wrapped in
    text
    []
  3. Named Parameters — Referenced by name, wrapped in
    text
    {}
  4. Required Named — Named but mandatory, uses
    text
    required
    keyword

1. Required Positional Parameters

These must always be provided in the exact order they are defined.

dart
// Both parameters are required and positional
String greet(String name, int age) {
  return 'Hello $name, you are $age years old';
}

greet('Alice', 30);     // ✅ Works
// greet('Alice');       // ❌ Error: missing argument
// greet(30, 'Alice');   // ❌ Error: wrong types (order matters)

2. Optional Positional Parameters
text
[]

Wrapped in square brackets. Can be omitted — defaults to

text
null
unless a default value is provided.

dart
String greet(String name, [int? age, String title = 'Mr.']) {
  if (age != null) {
    return 'Hello $title $name, age $age';
  }
  return 'Hello $title $name';
}

greet('Alice');              // ✅ 'Hello Mr. Alice'
greet('Alice', 30);          // ✅ 'Hello Mr. Alice, age 30'
greet('Alice', 30, 'Dr.');   // ✅ 'Hello Dr. Alice, age 30'
// greet('Alice', 'Dr.');    // ❌ Can't skip age (positional order)

3. Named Parameters
text
{}

Wrapped in curly braces. Referenced by name, so order doesn't matter. Optional by default.

dart
String greet({String? name, int? age, String title = 'Mr.'}) {
  return 'Hello $title ${name ?? "Guest"}, age ${age ?? "unknown"}';
}

greet();                              // ✅ 'Hello Mr. Guest, age unknown'
greet(name: 'Alice');                 // ✅ 'Hello Mr. Alice, age unknown'
greet(age: 30, name: 'Alice');        // ✅ Order doesn't matter
greet(title: 'Dr.', name: 'Alice');   // ✅ Skip age entirely

4. Required Named Parameters

Use the

text
required
keyword to make named parameters mandatory.

dart
class User {
  final String name;
  final String email;
  final int? age;

  // name and email are required, age is optional
  User({
    required this.name,
    required this.email,
    this.age,
  });
}

User(name: 'Alice', email: 'alice@mail.com');           // ✅
User(name: 'Alice', email: 'alice@mail.com', age: 30);  // ✅
// User(name: 'Alice');  // ❌ Error: 'email' is required

Mixing Parameters

You can mix required positional with either named OR optional positional (but not both).

dart
// ✅ Required positional + Named parameters
void sendEmail(String to, {String? subject, required String body}) {
  print('To: $to, Subject: $subject, Body: $body');
}
sendEmail('alice@mail.com', body: 'Hello!', subject: 'Greetings');

// ✅ Required positional + Optional positional
void log(String message, [String level = 'INFO', DateTime? timestamp]) {
  print('[$level] $message at ${timestamp ?? DateTime.now()}');
}
log('Server started');
log('Error occurred', 'ERROR');

// ❌ Cannot mix optional positional [] and named {} in same function
// void invalid(String a, [int? b], {String? c}) {} // Compile error!

Key Differences

FeatureRequired PositionalOptional Positional
text
[]
Named
text
{}
Required Named
Syntax
text
fn(int a)
text
fn([int? a])
text
fn({int? a})
text
fn({required int a})
Must provideYesNoNoYes
Order mattersYesYesNoNo
Default valueNot applicableYes (
text
= value
)
Yes (
text
= value
)
Not applicable
NullableOnly if
text
Type?
Usually
text
Type?
Usually
text
Type?
Can be non-null
Caller clarityLow (just values)LowHigh (named)High (named)

Best Practices

dart
// ✅ Use required named for constructors (Flutter convention)
class CustomButton extends StatelessWidget {
  const CustomButton({
    super.key,
    required this.label,
    required this.onPressed,
    this.color = Colors.blue,  // Optional named with default
  });

  final String label;
  final VoidCallback onPressed;
  final Color color;
}

// ✅ Use positional for simple functions with 1-2 params
int add(int a, int b) => a + b;

// ✅ Use named params when function has 3+ parameters
void configureApp({
  required String appName,
  required String apiUrl,
  bool debugMode = false,
  Duration timeout = const Duration(seconds: 30),
}) { }

// ✅ Use optional positional for convenience overloads
void log(String message, [String? tag]) {
  print('[${tag ?? 'APP'}] $message');
}

Key Insight: Flutter's widget constructors almost exclusively use required named parameters for clarity. Positional parameters are preferred for simple utility functions with 1-2 arguments.