How does a function return a Type

Every function declaration must specify a return Type. If we specify a function “void”, then it returns void. That means it returns nothing. However, if we specify that the return type should be String, then the function must return a String value.

We have already discussed two kinds of functions. The first kind is simple. It places a set of instructions inside the function body. When we call the function, the instructions are carried out. The second kind takes inputs making function more adaptable.

Now we are going to discuss third kind of function that returns a Type, or value.

Not only in Dart, or Flutter Framework, but in every programming language, we frequently use a function that returns a specified “Type”. If you are a beginner please read the articles that explain what is “Type” in Dart and Flutter. We have also discussed before how we can implement the “Type”.

Let us consider a simple Dart function that returns nothing. That means it is a void.

void main() {
  
  returnNothing(); // output: Do something
  
}
void returnNothing() {
  doSomething();
}
void doSomething() {
  print('Do something');
}

The void function returnNothing() calls another function doSomething(). Since the function doSomething() just prints a statement, the returnNothing() function returns no “Type”, but just prints out the statement.

However, we might categorically specify the function “Type” when we declare the function.

Consider this example.

void main() {  
  instruct();
}

void instruct() {
  print('${add()}');
  print('${subtract()}');
  print('${multiply()}');
  print('${divide()}');
}

int add() => 1 + 2;
int subtract() => 2 - 1;
int multiply() => 2 * 3;
int divide() => 4 ~/ 2;

/**
##output##
3
1
6
2
 */

We have first called a function instruct() inside our top-level function main().

The void function instruct() has then called four functions inside its function-body. They are add(), subtract(), multiply(), and divide().

Watch these four functions. While declaring they all specify the data type. They categorically specify that integer values should be returned. Hence the return “Type” is integer.

In Flutter, we will use such functions that return various data types. Sometimes they might be built-in data types. But sometimes, they might return a Widget, or Class which is a data type of an Object.

Consider another code in Dart. After that, we will see the implementation in Flutter.


void main() {
  
  BWidget b = BWidget();
  
  AWidget a = AWidget(b: b);
  
  print(a.runtimeType); // AWidget
  
  print(a.b); // Instance of 'BWidget'
  
  print(a.b.runtimeType); // BWidget
  
  var returningBWidget = a.getBWidget(a);
  
  print(returningBWidget.runtimeType); // AWidget
  
  print(returningBWidget.b); // Instance of 'BWidget'
  
  print(returningBWidget.b.runtimeType); // BWidget
  
}


class AWidget {
  BWidget? b;
  
  AWidget({this.b});
  
  AWidget getBWidget(AWidget a) {
    return a;
  }
  
}

class BWidget {}

In the above code we have shown a function that returns a user-defined “Type” which is a Class “AWidget”. We have already learned that every object has a “Type” which is nothing but its Class. A Class as a blueprint defines the properties and methods of that particular object.

As a result, in the above code, we see two objects – a and b. The object a has a type “AWidget”. And, the b object has a type “BWidget”.

Now, from the AWidget class we can return any Type. For brevity, in the above code, we have returned the “Type AWidget”.

But at the same way, we could have returned the type “BWidget” as well.

Therefore, we can change the above code and more functionality so that we can understand this custom returning “Type”.


void main() {
  
  BWidget b = BWidget();
  
  AWidget a = AWidget(b: b);
  
  BWidget b1 = BWidget(a: a);
  
  print(a.runtimeType); // AWidget
  
  print(a.b); // Instance of 'BWidget'
  
  print(a.b.runtimeType); // BWidget
  
  var returningBWidget = a.getBWidget(a);
  
  print(returningBWidget.runtimeType); // AWidget
  
  print(returningBWidget.b); // Instance of 'BWidget'
  
  print(returningBWidget.b.runtimeType); // BWidget
  
  var returningAWidget = a.getAWidget(b);
  
  print(returningAWidget.runtimeType); // BWidget
  
  print(returningAWidget.s); // I am BWidget
  
  print(b1.a); // Instance of 'AWidget'
  
  print(b1.s); // I am BWidget
  
  print(b1.a?.getAWidget(b)); // Instance of 'BWidget'
  
  print(b1.a?.getBWidget(a)); // Instance of 'AWidget'  
  
  print(b1.a?.getAWidget(b).a); // null
  
  print(b1.a?.getAWidget(b).a); // null
  
  print(b1.a?.getAWidget(b).runtimeType); // BWidget
  
  print(b1.a?.getBWidget(a).b); // Instance of 'BWidget'
  
  print(b1.a?.getBWidget(a).runtimeType); // AWidget
  
  print(b1.a?.getBWidget(a).getAWidget(b)); // Instance of 'BWidget'
  
  print(b1.a?.getBWidget(a).getBWidget(a)); // Instance of 'AWidget'
  
  print(b1.a?.getBWidget(a).getBWidget(a).b); // Instance of 'BWidget'
  
  print(b1.a?.getBWidget(a).getBWidget(a).getAWidget(b)); // Instance of 'BWidget'  
  
}


class AWidget {
  BWidget? b;  
  
  AWidget({this.b});
  
  AWidget getBWidget(AWidget a) {
    return a;
  }
  
  BWidget getAWidget(BWidget b) {
    this.b = b;
    return b;
  }
  
}

class BWidget {
  String s = 'I am BWidget';
  AWidget? a;
  
  BWidget({this.a});
}

So we can create more classes and play around to see how we can return various types of data that includes another objects also. Not only that, how objects are chained together to call one type from another type, and so on.

What is return type in Flutter?

We can return any valid data type in Flutter. In fact, we can return any Widget as well, to make our code more readable and adaptable.

However, we must remember that the returned-data-type must match the return type of the function.

Just as we have seen in the Dart console, when we specify a data type in Flutter, we should return that certain data type.

Let us refactor the “Mood Swing App” and make it more reusable and adaptable.

Meanwhile let us take a look at the previous code snippet where we have repeated a lot of same thing.

import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';

import '../model/mood.dart';

class AppHomePage extends StatelessWidget {
  const AppHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final mood = Provider.of<Mood>(context);
    final color = Provider.of<Mood>(context);
    return Scaffold(
      backgroundColor: Colors.white70,
      appBar: AppBar(
        title: const Text('Mood Swing App'),
      ),
      body: Center(
        child: Row(
          children: [
            Expanded(
              child: Padding(
                padding: const EdgeInsets.all(18.0),
                child: GestureDetector(
                  onTap: () {
                    mood.changeMood();
                    color.changeColor();
                  },
                  child: Column(
                    children: [
                      Image.asset('images/face${mood.leftFaceIndex + 1}.jpg'),
                      Container(
                        padding: const EdgeInsets.all(5.0),
                        child: Text(
                          'Mood Changes with Color',
                          style: GoogleFonts.laila(
                            textStyle: Theme.of(context).textTheme.headline6,
                            fontSize: 20,
                            fontWeight: FontWeight.w700,
                            color: color.colors[color.leftIndex],
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ),
            Expanded(
              child: Padding(
                padding: const EdgeInsets.all(18.0),
                child: GestureDetector(
                  onTap: () {
                    mood.changeMood();
                    color.changeColor();
                  },
                  child: Column(
                    children: [
                      Image.asset('images/face${mood.rightFaceIndex + 1}.jpg'),
                      Container(
                        padding: const EdgeInsets.all(5.0),
                        child: Text(
                          'Mood Changes with Color',
                          style: GoogleFonts.laila(
                            textStyle: Theme.of(context).textTheme.headline6,
                            fontSize: 20,
                            fontWeight: FontWeight.w700,
                            color: color.colors[color.rightIndex],
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

In the above code, the bold section is repeated below. Certainly, we can avoid this repetition.

Hence, it makes our code reusable, and adaptable.

In addition we can consolidate everything inside a method that returns an Expanded Widget.

Therefore, we can refactor the code with the third kind of function that returns the specified data type which is here the Expanded Widget.

import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';

import '../model/mood.dart';

class AppHomePage extends StatelessWidget {
  const AppHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final mood = Provider.of<Mood>(context);
    final color = Provider.of<Mood>(context);
    return Scaffold(
      backgroundColor: Colors.white70,
      appBar: AppBar(
        title: const Text('Mood Swing App'),
      ),
      body: Center(
        child: Row(
          children: [
            expandMethod(mood, color, context),
            expandMethod(mood, color, context),
          ],
        ),
      ),
    );
  }

  /// A common function that returns data type Expanded
  /// later we can use that function

  Expanded expandMethod(Mood mood, Mood color, BuildContext context) {
    return Expanded(
      child: Padding(
        padding: const EdgeInsets.all(18.0),
        child: GestureDetector(
          onTap: () {
            mood.changeMood();
            color.changeColor();
          },
          child: Column(
            children: [
              Image.asset('images/face${mood.rightFaceIndex + 1}.jpg'),
              Container(
                padding: const EdgeInsets.all(5.0),
                child: Text(
                  'Mood Changes with Color',
                  style: GoogleFonts.laila(
                    textStyle: Theme.of(context).textTheme.headline6,
                    fontSize: 20,
                    fontWeight: FontWeight.w700,
                    color: color.colors[color.rightIndex],
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

As we can see in the above code, we have declared a function (which is method in a Class), which returns an Expanded Widget.

As a result, we can call the method twice inside the Row Widget.

child: Row(
          children: [
            expandMethod(mood, color, context),
            expandMethod(mood, color, context),
          ],
        ),

Subsequently, it has made our code more reusable and readable.

In addition, our “Mood Swing App” works perfectly fine. Just like before.


Flutter function second example
Flutter Mood Swing App

If you want to clone the project, please visit the respective GitHub repository.

What Next?

Books at Leanpub

Books in Apress

My books at Amazon

Courses at Educative

GitHub repository

Technical blog

Twitter

Comments

3 responses to “How does a function return a Type”

  1. […] the above code, we have used function as a first class citizen, or first class object. In other words, we have passed a function just […]

  2. […] addition, Flutter and Dart comes with plenty of methods that we can use to handle the […]

  3. […] the above code, we have used function as a first class citizen, or first class object. In other words, we have passed […]

Leave a Reply