◉_◉ Arslan Ali's blog

Functions and their parameters in Dart

So, a function is anything that can do something.

A bottle can store water for later usage.
A headphone can intensify an audio wave, and help you with the listening.
A blog can help you understand a concept. (And that's why you are here. :))

Unlike the real world, a function in a programming language has a definite structure to it.

A function in Dart looks like the following:

int factorial(int number) {
  return number < 1 ? number : number*factorial(number-1);
}

So a function has the following parts:

  1. Return type
  2. Parameter list
  3. Body

Dart is a strongly typed language, so one must specify the type of value that will be returned.

Parameter types:

Similarly, while specifying parameters, one must also include the type.

Normally, one can specify the parameters of a function in two ways: positional & named.

With positional parameters, while calling the function, one will send the arguments according to the position of the parameters. The order matters here!

void introduce(String name, int age) {
  print('My name is $name, and I\'m $age years old');
}

The only way to call this function is introduce('John', 23). If one changes the order of the arguments, it will generate a compile-time error.

In named parameters, each parameter has its own name/key, and while sending an argument, one has to specify the name/key as well.

void introduce({String name, int age}) {
  print('My name is $name, and I\'m $age years old');
}

Before digging deep into named parameters, one must be aware of the fact that Dart has something called Null Safety. Simply put, a variable can't be null in Dart.

int age = null; // Invalid code
int? myAge = null; // Valid code, `?` makes a variable nullable.

The function above doesn't guarantee that the arguments won't be null, so to make those nullable, one can use ? after the data type.

void introduce({String? name, int? age}) {
  print('My name is $name and my age is $age.');
}

Now, the function can be called using the names/keys, and the order doesn't matter. The following two ways of calling the function are both valid:

introduce(name: 'Stephen', age: 28);
introduce(age: 34, name: 'Kevin');

Well, one might ask the question why ? wasn't needed in the case of positioned parameters.

The concept of nullability depends on whether a parameter is required or not. If a parameter is required by default, ? isn't needed to make it null-safe.

In the case of positioned parameters, those are required by default. If one misses any of the positioned parameters, there will be a compile-time error, so nothing is needed as far as null safety is concerned.

For named parameters, those aren't required by default, so one has to take care of the null safety.

The required keyword:

One workaround is to use the keyword required to make sure that the named parameters are required, and thus, ? is no more needed.

void introduce({required String name, required int age}) {
  print('My name is $name and my age is $age.');
}

So far, the information about the parameters can be summed up in the following table:

Parameter Type Required by default Order matters How to pass How to make required

| Named Parameters | Yes | Yes | Only values | Required by default | Positioned Parameters | No | No | Key-value pairs | Using the required keyword

Setting a default value for a parameter:

One doesn't have to make a parameter required because of Null Safety in Dart. If there is a default value for a parameter, it could never be null, and thus we can omit required in the case of named parameters.

void introduce({required String name, int age=30}) {
  print('My name is $name and my age is $age.');
}

As one can see, name is required as its value can't be null, and for age, its default value is 30 by default so while calling the above function, one can decide not to pass anything for it, and the call will still work.

introduce(age: 48, name: 'John')
introduce(name: 'Elisa') // Works as age has a default value to it.
introduce(age: 31) // Doesn't work as name is always required.

In the case of positional parameters, one can also set the default values, and the default value can only be set for those parameters that are optional.

The way to make a parameter optional is to surround it with square brackets:

void introduce(String name, [int age]) {
  print('My name is $name, and my age is $age.');
}

In the function above, age is optional. One can omit this parameter while calling introduce.

Once a parameter has been marked optional(by using the square brackets), its default value can be set like following:

void introduce(String name, [int age=40]) {
  print('My name is $name, and my age is $age.');
}

Setting the default values for both the parameters will go like this:

void introduce([String name='John', int age=40]) {
  print('My name is $name, and my age is $age.');
}

A combination of named & positional parameters is also possible in Dart:

void formallyIntroduce(String firstName, String lastName, {int age=28}) {
  print('My name is $lastName, $firstName; my age is $age.');
}

To call the function above, we can pass the arguments like: formallyIntroduce('John', 'Doe', age: 40)

So, to summarize all the things about parameters:

  1. Dart has two types of parameters: named parameters & positional parameters
  2. The named parameters are required by default, and those can't be null.
  3. The positional parameters are not required by default, so one either has to make those optional using ? after the type or mark them as required.
  4. In the case of the named parameters, those can be set optional by surrounding those with square brackets, and once marked optional, the default values can be set for those. (Only optional parameters can have default values.)
  5. One can't have optional named parameters & positional parameters in the same function, so the function: void introduce([int age], {String name='John'}) will be an invalid function in Dart.

#dart #functions #parameters #programming