Chapters

Hide chapters

Dart Apprentice: Fundamentals

First Edition · Flutter · Dart 2.18 · VS Code 1.71

Dart Apprentice: Fundamentals

Section 1: 16 chapters
Show chapters Hide chapters

3. Types & Operations
Written by Jonathan Sande

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Life is full of variety, and that variety expresses itself in different ways. What type of toothpaste do you use? Spearmint? Cinnamon? What’s your blood type? A? B? O+? What type of ice cream do you like? Vanilla? Strawberry? Praline pecan fudge swirl? Having names for all of these different things helps you talk intelligently about them. It also helps you to recognize when something is out of place. After all, no one brushes their teeth with praline pecan fudge swirl. Though it does sound kind of nice.

Programming types are just as useful as real-life types. They help you to categorize all the different kinds of data you use in your code.

In Chapter 2, “Expressions, Variables & Constants”, you learned how to name data using variables and also got a brief introduction to Dart data types. In this chapter, you’ll learn even more about types and what you can do with them.

Data Types in Dart

In Dart, a type is a way to tell the compiler how you plan to use some data. By this point in this book, you’ve already seen the following types:

  • int
  • double
  • num
  • dynamic
  • String

The last one in that list, String, is the type used for text like 'Hello, Dart!'.

Just as you don’t brush your teeth with ice cream, Dart types keep you from trying to do silly things like dividing text or removing whitespace from a number.

Dart has even more built-in types than just the ones listed above. The basic ones, such as int, double, and num will serve you adequately in a great variety of programming scenarios, but when working on projects with specific needs, it’ll be convenient to create custom types instead. A weather app, for example, may need a Weather type, while a social media app may need a User type. You’ll learn how to create your own types in Chapter 5, “Control Flow”, and Chapter 8, “Classes”.

As you learned in Chapter 2, “Expressions, Variables & Constants”, types like int, double and num are subclasses, or subtypes, of the Object type. Object defines a few core operations, such as testing for equality and describing itself. Every non-nullable type in Dart is a subtype of Object, and as a subtype, shares Object’s basic functionality.

Note: You’ll learn about nullable types in Chapter 11, “Nullability”.

Type Inference

In the previous chapter, you also got a sneak peek at type inference, which you’ll look at in more depth now.

Annotating Variables Explicitly

It’s fine to always explicitly add the type annotation when you declare a variable. This means writing the data type before the variable name.

int myInteger = 10;
double myDouble = 3.14;

Creating Constant Variables

Declaring variables the way you did above makes them mutable. If you want to make them immutable, but still keep the type annotation, you can add const or final in front.

const int myInteger = 10;
const double myDouble = 3.14;
final int myInteger = 10;
final double myDouble = 3.14;

Letting the Compiler Infer the Type

While it’s permissible to include the type annotation as in the example above, it’s redundant. You’re smart enough to know that 10 is an int and 3.14 is a double, and it turns out the Dart compiler can deduce this as well. The compiler doesn’t need you to explicitly tell it the type every time — it can figure the type out on its own through a process called type inference. Not all programming languages have type inference, but Dart does — and it’s a key component behind Dart’s power as a language.

const myInteger = 10;
const myDouble = 3.14;

Checking the Inferred Type in VS Code

Sometimes, it can be useful to check the inferred type of a variable or constant. You can do this in VS Code by hovering your mouse pointer over the variable name. VS Code will display a popover like this:

Checking the Type at Runtime

Your code can’t hover a mouse pointer over a variable to check the type, but Dart does have a programmatic way of doing nearly the same thing: the is keyword.

num myNumber = 3.14;
print(myNumber is double);
print(myNumber is int);
true
false
print(myNumber.runtimeType);

Type Conversion

Sometimes, you’ll have data in one type, but need to convert it to another. The naïve way to attempt this would be like so:

var integer = 100;
var decimal = 12.5;
integer = decimal;
A value of type 'double' can't be assigned to a variable of type 'int'.
integer = decimal.toInt();

Operators With Mixed Types

So far, you’ve only seen operators acting independently on integers or doubles. But what if you have an integer that you want to multiply with a double?

const hourlyRate = 19.5;
const hoursWorked = 10;
const totalCost = hourlyRate * hoursWorked;
const totalCost = (hourlyRate * hoursWorked).toInt();
Const variables must be initialized with a constant value.
final totalCost = (hourlyRate * hoursWorked).toInt();

Ensuring a Certain Type

Sometimes you want to define a constant or variable and ensure it remains a certain type, even though what you’re assigning to it is of a different type. You saw earlier how you can convert from one type to another. For example, consider the following:

const wantADouble = 3;
final actuallyDouble = 3.toDouble();
const double actuallyDouble = 3;
const wantADouble = 3.0;

Casting Down

The image below shows a tree of the types you’ve encountered so far. Object is a supertype of num and String, and num is a supertype of int and double. Conversely, int and double are subtypes of num, which is a subtype of Object.

Ejdovp nal ann Cfvalm roajka

num someNumber = 3;
print(someNumber.isEven);
The getter 'isEven' isn't defined for the type 'num'.
final someInt = someNumber as int;
print(someInt.isEven);
num someNumber = 3;
final someDouble = someNumber as double;
_CastError (type 'int' is not a subtype of type 'double' in type cast)
final someDouble = someNumber.toDouble();

Exercises

  1. Create a constant called age1 and set it equal to 42. Create another constant called age2 and set it equal to 21. Check that the type for both constants has been inferred correctly as int by hovering your mouse pointer over the variable names in VS Code.
  2. Create a constant called averageAge and set it equal to the average of age1 and age2 using the operation (age1 + age2) / 2. Hover your mouse pointer over averageAge to check the type. Then check the result of averageAge. Why is it a double if the components are all int?

Object and dynamic Types

Dart grew out of the desire to solve some problems inherent in JavaScript. JavaScript is a dynamically-typed language. Dynamic means that something can change, and for JavaScript that means the types can change at runtime.

var myVariable = 42;
myVariable = "hello";
var answer = myVariable * 3; // runtime error
var myVariable = 42;
myVariable = 'hello'; // compile-time error
dynamic myVariable = 42;
myVariable = 'hello'; // OK
var myVariable; // defaults to dynamic
myVariable = 42;      // OK
myVariable = 'hello'; // OK
Object? myVariable = 42;
myVariable = 'hello'; // OK

Challenges

Before moving on, here are some challenges to test your knowledge of types and operations. It’s best if you try to solve them yourself, but solutions are available with the supplementary materials for this book if you get stuck.

Challenge 1: Teacher’s Grading

You’re a teacher, and in your class, attendance is worth 20% of the grade, the homework is worth 30% and the exam is worth 50%. Your student got 90 points for her attendance, 80 points for her homework and 94 points on her exam. Calculate her grade as an integer percentage rounded down.

Challenge 2: What Type?

What’s the type of value?

const value = 10 / 2;

Key Points

  • Type conversion allows you to convert values of one type into another.
  • When doing operations with basic arithmetic operators (+, -, *, /) and mixed types, the result will be a double.
  • Type inference allows you to omit the type when Dart can figure it out.
  • Dart is an optionally-typed language. While it’s preferable to choose statically-typed variables, you may write Dart code in a dynamically-typed way by explicitly adding the dynamic type annotation in front of variables.
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2024 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now