06 Basic Syntax & Type Variables How Dart Represents Information

06 Basic Syntax & Type Variables How Dart Represents Information #

Hello, I am Chen Hang.

In the second preview article “Dart Language Overview” of this column, we briefly got to know Dart, which is an excellent programming language. So what makes Dart different from other languages? And how can I quickly get started with it based on my experience with other programming languages?

Today, let’s start learning Dart from its most important components, namely, basic syntax and typed variables.

First Experience with Dart #

To have a simple experience with Dart, we can open a browser and create a new main.dart file directly on repl.it (of course, you can also install the Dart SDK on your computer to experience the latest syntax).

Below is a basic “hello world” example. I declare a function with an int parameter and print out this parameter using string interpolation:

printInteger(int a) {
  print('Hello world, this is $a.'); 
}

main() {
  var number = 2019; 
  printInteger(number); 
}

Then, click the “run” button in the editor. The command line will output:

Hello world, this is 2019.

Like most compiled languages, Dart requires a main function as the entry point for execution.

After learning how to run Dart code easily, let’s take a look at the basic variable types in Dart.

Variables and Types in Dart #

In Dart, we can declare a variable using var or a specific type. When using var, the type is inferred by the compiler. However, you can also define variables with static types to express your intent more clearly to the editor and the compiler. This allows them to provide code completion and compile warnings based on these static types.

By default, uninitialized variables have a value of null. Therefore, we don’t have to worry about determining whether an undefined variable is undefined or null and write lengthy if statements.

Dart is a statically typed language, where all types are objects and inherit from the top-level type Object. This means that all variable values are instances (objects) of a class, including numbers, booleans, functions, and null.

Dart has built-in basic types such as num, bool, String, List, and Map. You can use them to declare variables without importing other libraries. Let me introduce them one by one.

num, bool, and String #

As the most commonly used types in programming languages, I will introduce these three basic types together: num, bool, and String.

In Dart, the numeric type num has only two subclasses: int, which represents integer types, and double, which is an abstraction of floating-point numbers. In most cases, their precision and range are sufficient for our needs.

int x = 1;
int hex = 0xEEADBEEF;
double y = 1.1;
double exponents = 1.13e5;
int roundY = y.round();

In addition to common arithmetic operators such as +, -, *, /, and bitwise operators, you can use methods inherited from num, such as abs(), round(), to perform absolute value calculations and rounding.

In fact, if you open the official documentation or view the source code, you will find that these common operators are also inherited from num:

Figure 1: Operators in the num type

If you have advanced mathematical computation needs that num cannot satisfy, you can try using the dart:math library. This library provides advanced functions such as trigonometric functions, exponentiation, logarithms, and square roots.

To represent boolean values, Dart uses a type called bool. In Dart, there are only two objects that have a bool type: true and false. They are both compile-time constants.

Dart is statically typed, so we cannot use code like if (nonbooleanValue) or assert(nonbooleanValue) that works in JavaScript. Instead, we should explicitly check the value.

For example, to check if a variable is 0, in Dart, we need to explicitly compare it with 0:

// Check if it's 0.
var number = 0;
assert(number == 0);
// assert(number); Error

Dart’s String consists of UTF-16 strings. Similar to JavaScript, you can use either single or double quotes to construct string literals, and you can embed variables or expressions in a string using ${expression}. If the expression is an identifier, you can omit the {}.

Here is an example of embedding an expression. We convert the word ‘cat’ to uppercase and put it into the declaration of variable s1:

var s = 'cat';
var s1 = 'this is an uppercased string: ${s.toUpperCase()}';

To concatenate strings, Dart uses the built-in operator +. For example, the following statement declares a string 'Hello World!' as expected:

var s2 = 'Hello' + ' ' + 'World!';

For constructing multi-line strings, you can use triples of single or double quotes, similar to Python:

var s3 = """This is a
multi-line string.""";

List and Map #

In Dart, the commonly used array and dictionary types in other programming languages correspond to List and Map, respectively, and are collectively referred to as collection types. Their declaration and usage are simple and similar to how they are used in JavaScript.

Now let’s look at a code example together.

  • In the first half of the code example, we declare and initialize two List variables. After adding a new element to the second variable, we call its iteration method to print its internal elements one by one.
  • In the second half of the code example, we declare and initialize two Map variables. After adding two key-value pairs to the second variable, we again call its iteration method to print its internal elements one by one.
var arr1 = ["Tom", "Andy", "Jack"];
var arr2 = List.of([1,2,3]);
arr2.add(499);
arr2.forEach((v) => print('${v}'));

var map1 = {"name": "Tom", 'sex': 'male'}; 
var map2 = new Map();
map2['name'] = 'Tom';
map2['sex'] = 'male';
map2.forEach((k,v) => print('${k}: ${v}')); 

The elements in the containers also need to have types. For example, the type of arr2 in the code above is List, while the type of map2 is Map. Dart will automatically infer the types based on the context, so any elements you subsequently add to the container must adhere to this type.

If the type inferred by the compiler does not match the expectation, you can explicitly mark the type when declaring it. This not only makes code suggestions more friendly, but more importantly, it allows the static analyzer to help check any errors in literals and eliminate type mismatch-related risks or bugs.

Using the above code as an example, if you add a floating-point number to the arr2 collection using arr2.add(1.1), although it is semantically valid, the compiler will prompt a type mismatch error, resulting in a compilation failure.

Similar to the Java language, you can add constraints to the type when initializing a collection instance, which can also be used to determine the type of the collection subsequently.

Does the following code make the semantics clearer after adding type constraints?

var arr1 = <String>['Tom', 'Andy', 'Jack'];
var arr2 = new List<int>.of([1,2,3]);
arr2.add(499);
arr2.forEach((v) => print('${v}'));
print(arr2 is List<int>); // true

var map1 = <String, String>{'name': 'Tom','sex': 'male',};
var map2 = new Map<String, String>();
map2['name'] = 'Tom';
map2['sex'] = 'male';
map2.forEach((k,v) => print('${k}: ${v}')); 
print(map2 is Map<String, String>); // true

Constant Definitions #

If you want to define immutable variables, you need to use the final or const keyword before the variable declaration:

  • const indicates a value that can be determined during compilation.
  • final, on the other hand, allows the variable to have a value determined at runtime, but once it is determined, it cannot be changed.

Here are typical examples of declaring const and final constants:

final name = 'Andy';
const count = 3;

var x = 70;  
var y = 30;
final z = x / y;

As you can see, const is used to define compile-time constants (literal fixed values), while final is used to define runtime constants.

Summary #

With the introduction above, I believe you have gained a preliminary understanding of the basic syntax and type system of Dart. These initial impressions will help you understand the basic ideas behind Dart’s language design and quickly get started based on your existing programming language experience.

As for control flow syntax, such as if-else, for, while, do-while, break/continue, switch-case, assert, I won’t explain them one by one here because they are similar to other programming languages. You need to learn more about Dart language features gradually in the process of using it. In our journey of using Dart, the official documentation is our most important learning reference.

Congratulations! You have taken the first step in learning the Dart language. Next, let’s briefly review today’s content to deepen your memory and understanding:

  • In Dart, all types are object types and inherit from the top-level type Object, so all variables are objects, including numbers, booleans, functions, and null.
  • Uninitialized variables have a value of null.
  • Specify the type of variables so that the editor and compiler can better understand your intention.

Thought-provoking question #

How can we make the elements of the List and Map collection types support multiple types (e.g., int, double)? And how can we determine the type when iterating over the collection?

Feel free to leave a comment in the comment section to share your perspective, and I’ll be waiting for you in the next article! Thank you for listening, and feel free to share this article with more friends to read together.