Dart  [Part-1]: Datatypes and keywords

Dart [Part-1]: Datatypes and keywords

Introduction to Dart and understanding data types and keywords in Dart

Introduction

Hello World!

Flutter is an open-source UI software development toolkit created by Google; it is a rapidly growing framework for cross-platform development. Cross-platform development means developing apps for mobile devices, desktops, and the web from a single codebase.

Flutter uses the Dart programming language under the hood. In this beginner-friendly blog, we will learn the fundamentals of the Dart programming language. We will be covering a brief history of Dart, and then move directly to data types and keywords provided by Dart.

Why was Dart created in the first place?

Dart was unveiled in 2011. It was designed with a focus on improving web development by addressing limitations in JavaScript. Dart aimed to offer a more structured and efficient alternative for building complex, large-scale web applications compared to JavaScript, which is dynamically typed, lacks certain features and often poses challenges for developers working on ambitious projects (However, JavaScript is still the most widely used language for web development in the world).

Dart shines prominently in frontend development, particularly with the Flutter framework, which utilizes Dart to build natively compiled mobile, web, and desktop applications from a single codebase.

However, Dart is not limited to front-end development. It can also be used for backend development through frameworks like Aqueduct to create RESTful APIs and handle complex backend logic. This allows developers to build full-stack applications using Dart.

What is unique about Dart?

Let us look at some of Dart's characteristics in the following section.

Object-Oriented

Dart is an object-oriented programming (OOP) language. But what exactly is an object-oriented programming (OOP) language? Well, it is a programming language that supports the creation of objects- data structures with data fields (simply variables) and methods (also called functions) to build applications.

Dart powers Flutter (which might be why you're learning Dart, right?), and the entire Flutter framework is based on OOP principles like Inheritance, Abstraction, Polymorphism, and Encapsulation.

Note: If you are getting introduced to the above-stated terms for the first time, simply leave it (No Worries!). Just keep in mind that OOP languages allow us to create objects (What are objects? We'll see later). Object-oriented programming is an entirely different topic on its own; we might cover it in a different article.

Static type system

Dart is a statically typed programming language, which means that Dart ensures that the values of variables match their static types (data types defined at the time of writing code). This feature is called type-safety or sound-typing. Type safety is one of the most critical features of Dart.

Note: People from web development backgrounds can think of this feature as the same as TypeScript, as JavaScript is dynamically typed (that means the data type of a variable is not fixed; it can change at any time inside the code without the compiler giving any errors).

Sound Null Safety

In Dart, variables can never be null unless the developer says they can be. This can help avoid null exceptions that might occur at runtime. This is how we can declare a null variable.

/* '?' indicates that although the variable 'num' is an integer, but
it can also be null */
int? num;
int nonNullNum; // this variable must always be an integer

Note: JavaScript has no built-in mechanisms to check for null variables. Hence, the developers need to be very careful while dealing with null in JavaScript (this was another reason for the introduction of TypeScript in web development).

In the following sections, we will learn about some common data types in Dart, which you might have seen in other programming languages, primarily JavaScript (too many similarities, Huh!)

Data types in Dart

Preliminary Note: Everything in Dart is an object. You might not know what an object is, and it is completely fine. Objects are not in the scope of this article. Just remember that there is some super-set called an object that encompasses everything else in Dart (even functions).

Dart supports many data types similar to other programming languages, such as integers, strings, and booleans. However, Dart also provides unique data types like records, maps, lists, and sets. We will look at all of these in detail.

Note: The syntax to declare any variable (something that stores data) is dataType variableName = variableValue

Primitive data types in Dart

Below are the primitive datatypes provided by Dart. All of these are self-explanatory; hence, we won't be going into their details (The exciting stuff comes after this!).

  1. int : Store numbers no larger than 64 bits

  2. double : Stores 64-bit floating point numbers

  3. bool : Stores boolean values (either true or false)

  4. String : Stores strings (in double quotes or single quotes)

     int number = 100; // integer
     double weight = 108.10; // double
     bool isCitizenOfIndia = true; // boolean
     // Both are valid strings
     String nameWithDoubleQuotes = "Abhijeet";
     String nameWithSingleQuotes = 'Abhijeet';
    

Note: Did you notice that the String datatype starts with a capital letter, whereas other datatypes start with a small letter? That's just how Dart was designed, and we cannot do anything about it. Try to remember it.

Collections in Dart

Besides the commonly used data types, Dart also offers collections. "Collections" is a general term that refers to data types (or technically data structures) that store a group of related data together.

Lists

Just like other programming languages have arrays, Dart has lists, which store data in a sequence.

// Syntax: List <another_datatype> listName = [];
List<String> listOfCities = ["New York", "New Delhi", "Boston"];
List<int> listOfMarks = [23, 45, 90];
List<double> listOfHeights = [100.9, 23.45, 32.109];

We can create a list of any fundamental/primitive or derived data type. For example, we can have a list of list of strings.

List<List<String>> names = [
    ["Abhijeet"],
    ["Abhishek", "Kumar", "Gupta"],
    ["John", "Doe"],
];

We can also create a list consisting of different data types together. Remember, I told you earlier that everything in Dart is an object.

List<Object> everything = ["fskhg",true,235, 78.0];

Sets

Need a data structure that stores unique data only? Dart has got you Sets. A set in Dart is an unordered collection of unique items.

Set<int> numbers = {23,45,6,50,10}; // Stores only unique values
List<int> numbers2 = [23, 34, 23, 10]; // Can store duplicate values

Maps

Maps are collections (or data structures if you wish to call it that) that store data in key-value pairs. Both the keys and values can be of any type.

// Syntax: Map<data_type1, data_type2> mapName = {};

// A map of Strings and integers
Map<String, int> studentMarks = {
    "Smith" : 89,
    "Abhijeet" : 94,
    "Alizeh" : 78
};

// A map of integers and booleans
Map<int, bool> isEven = {
    2 : true,
    5 : false,
    11 : false
};

Note: Lists are declared using square brackets ([]) whereas Maps and Sets are declared using curly braces ({}).

Dart provides more data types, such as Runes and Symbols, but they are pretty uncommon and very specific; therefore, they are not covered here. Moreover, there is something called Records in Dart versions beyond 3.0, but they are not covered here to keep this article beginner-friendly.

Declaring variables in Dart

Declaring a variable is pretty straightforward; you have done it a thousand times. Just put a keyword (usually the data type) followed by the variable name.

// Syntax to declare a variable => keyword/data-type variableName;
int number;
String name;

However, it is not always necessary to define the variable's data type beforehand; sometimes, the developers find it more practical and valuable to have the Dart system (or compiler) infer the data type during the run time. Dart provides specific keywords for this, and we will look into each in the following section.

Keywords in Dart

var

The var keyword is used when the data stored in the variable can take any potential value. The Dart compiler infers (understands on its own) the data type during compile time (when the code is being compiled). This means that the variable type gets fixed when its value is assigned.

var anything = 10; // Data type of "anything" is integer
anything = "Abhijeet"; // This will give an Error
// Data type once inferred by the compiler cannot change now

Note: People coming from the JavaScript background might get confused here. Let me clear up the confusion.
var keyword in JavaScript gives dynamic type to the variable, which is checked during the runtime (and not during compile time). So, we can change the type of data stored in the variable without errors.
However,
var keyword in Dart works a little differently; the data type cannot be changed later if the compiler has inferred it once.

// IN JAVASCRIPT
// variables declared using `var` keyword can change their datatype 
var name = 10; // datatype is integer
name = "Abhijeet"; // datatype is now string
// IN DART
// variables declared using `var` keyword can't change their datatype
var name = 10; // datatype inferred by the compiler as integer
name = "Abhijeet"; // ERROR: A value of type String cannot be 
// assigned to a variable of type integer

dynamic

The dynamic keyword stores data with dynamic typing. This means that the type of data being stored in the variable is inferred during the run time (when the dart program is run after being compiled).

This is similar to the var keyword of JavaScript.

// In Dart, variables declared using `dynamic` keyword can change 
// their datatypes at any later stage in the code

dynamic name = 10; // datatype is integer
name = "Abhijeet"; // datatype is now String
name = ['new york', 'boston']; // datatype is now List<String>
name = ["Abhijeet", 23]; // datatype is now List<dynamic>

Note: Evidently, the dynamic keyword contradicts Dart's type-safety feature. Therefore, you should avoid using the dynamic keyword wherever possible.

The difference between dynamic and var

The only similarity between var and dynamic is that the values stored in variables declared using both these keywords can be changed at any later stage in the code. Let us talk about the differences between the two.

var
The data type is checked during the compile time.
The data type cannot be changed later on.

dynamic
The data type is checked during the run time.
The data type can be changed later on.

final

The final keyword can hold any value, but it must not be changed later. The data stored in a final variable cannot be changed (hence the term "constant"). The data type is inferred at the runtime.

final name = "Abhijeet"; // datatype inferred as String
name = "Shanaya"; // ERROR: A final variable can only be set once
name = 10; // ERROR: A value of type integer cannot be assigned
// to a variable of type String

final names = ["Abhi","John"]; // datatype inferred List<String>
final list = ["Abhijeet", true]; // datatype inferred List<Object>

The more practical use of final variables is to store runtime constants. A runtime constant is a constant value known while the program is running. For instance, some runtime constants are the current date or the response from an external API.

final date = DateTime.now(); // Gives the current date
final response =  await getWeatherData(); // Gives current weather
// from an external API

/* Note: If you do not understand the `await` keyword here, Just 
ignore it. It is used when dealing with asynchronous operations
(more on it in some other article) */

const

Just like the final keyword, the const keyword is also used to store values that cannot be changed later. The data type is inferred at the compile time (just like var), and hence, any constant that is not a compile-time constant cannot be assigned to a const variable. For instance, API responses and current dates are not compile-time constants.

const name = "Abhijeet"; // datatype inferred as String
name = "Shanaya"; // ERROR: A const variable can only be set once
name = 10; // ERROR: A value of type integer cannot be assigned
// to a variable of type String

const list = ["Abhijeet", true, 34]; // type inferred List<Object>

const date = DateTime.now(); // ERROR: Const variables must be 
// initialized with a constant value

The difference between final and const

The following comparison lists some similarities as well as differences between the final and the const keywords.

final
Value, once assigned, cannot be changed.
Datatype is inferred at the runtime.
It can store runtime constants such as API responses and current dates.

const
Value, once assigned, cannot be changed.
Datatype is inferred at the compile-time.
It can only store data that is constant at the compile-time.
A const variable must be initialized with a value.

Note: Remember that API responses are always handled using the keyword when handling asynchronous operations (Futures in Dart, similar to promises in JavaScript). And use the const keyword to assign constant values to a variable.

You can also specify the type while using the final and const keywords to avoid the type inference.

final String name = "Abhijeet";
const double grade = 7.54;

final List<int> list = [2,3,4,5];
const List<String> names = ["Abhijeet", "Anshika"];

final List<Object> anything = ["Abhijeet", true, 45.8, 455];
const List<Object> anything2 = ["Anshika", false, 95.8, 476];

Conclusion

In this introductory article, we delved into the basics of Dart programming. We explored Dart's object-oriented nature, its crucial role in powering Flutter, and key features such as static type system and sound null safety. Along with the standard data types, such as Lists, Sets, and Maps, providing a brief overview, the article also elucidated variable declaration using keywords like var, dynamic, final, and const, focusing on clarifying the distinctions between these for beginners.

In conclusion, I hope this article served as a concise foundation for beginners and set the stage for more in-depth exploration in future series installments.

Resources to Learn more

You can refer to the following resources to learn more about the Dart programming basics and practice the basic syntax and other concepts.

I will see you at the next one.
Till then, Goodbye.