Dart Fundamentals: Variables, Functions & Operators | Flutter Course (Ch. 2)
Welcome to Chapter 2! In the last chapter, we learned why Flutter is a revolutionary framework. Now, we're going to learn the language that powers it: Dart.
Don't be intimidated if you've never coded before! Dart was designed by Google to be easy to learn, familiar to developers, and perfectly optimized for building user interfaces. If you've ever seen JavaScript, Java, or C#, you'll feel right at home. If you haven't, that's okay too! We're starting from zero.
This chapter is our "bootcamp" for Dart. We'll cover the fundamental building blocks you need before you can build a real app. We're going to focus on the absolute essentials: variables, data types, functions, and operators.
Note: To practice, I highly recommend using DartPad. It's a free, online code editor that lets you run Dart code right in your browser. No installation needed!
📖 Chapter 2: Table of Contents
1. The `main()` Function: Your App's Front Door
Every single Dart application—from a simple command-line script to a
complex Flutter app—starts in the same place: the main()
function.
Think of it as the main entrance to a building. When you run your program,
Dart looks for main() and executes whatever is inside it.
Here is the "Hello, World!" of Dart. This is the simplest program you can write:
void main() {
print('Hello, World!');
}
Let's break this down:
-
void: This is a "return type." It just means "this function doesn't return any data." -
main(): This is the special name of the function. -
{ ... }: These curly braces define the "body" of the function—all the code that belongs to it. -
print('Hello, World!');: This is a built-in Dart function that prints a line of text to the console. -
;: The semicolon. Dart uses semicolons to mark the end of a statement. You'll put one at the end of almost every line of code.
Go ahead! Paste that into DartPad and hit "Run." You'll see "Hello, World!" appear in the console. Congratulations, you're officially a Dart programmer!
2. Writing Notes: An Introduction to Comments
As your code gets more complex, you'll want to leave notes for yourself or for other developers. These are called comments, and the program ignores them.
// This is a single-line comment. It's great for quick notes.
/*
This is a multi-line comment.
It's perfect for writing longer
explanations.
*/
void main() {
// This print statement is about to run.
print('Hello, Comments!');
}
Use comments generously! It's impossible to "over-comment" when you're learning.
Variables: Storing Your Data
A variable is a container for data. Think of it as a labeled box where you can store a value to use later.
You create (or "declare") a variable by giving it a name. You can then
put a value into it using the = (assignment operator).
The `var` Keyword: Let Dart Guess
The easiest way to declare a variable in Dart is with the
var keyword.
void main() {
var name = 'Alice'; // Dart infers this is a String
var age = 30; // Dart infers this is an int
print(name); // Output: Alice
print(age); // Output: 30
}
This is called type inference. You're giving Dart a
value, and it's smart enough to "infer" or guess what type of data it is.
In this case, it knows 'Alice' is text (a String)
and 30 is a whole number (an int).
Once Dart has inferred a type, it's "locked in." You can't change it. This gives you safety.
var name = 'Alice';
// name = 123; // This will cause an ERROR!
// A value of type 'int' can't be assigned to a variable of type 'String'.
Explicit Types: Be Specific
You can also be more explicit and tell Dart exactly what type of data you plan to store. This is often better for code clarity.
String name = 'Bob';
int age = 42;
double price = 10.99;
bool isLoggedIn = true;
print(name);
print(age);
print(price);
print(isLoggedIn);
We'll cover what String, int,
double, and bool mean in the next section. For
now, just know that this is the most common way you'll see variables
declared in professional code because it's so clear and readable.
The `final` and `const` Keywords: Data That Doesn't Change
Sometimes, you want to create a variable that can never change. This is known as immutability, and it's a huge concept in Flutter.
Dart gives you two keywords for this: final and
const.
Use final when you don't know the value until the
program is running.
A final variable can only be set once. After that, it's
locked.
void main() {
final String name = 'Charlie';
// name = 'David'; // This will cause an ERROR!
// This is a common use case:
final DateTime now = DateTime.now(); // Gets the current time
print(now);
}
In the example above, now can be final because
we set it once and never change it. But it can't be const
because we don't know what the exact time will be until the code actually
runs.
Use const when you know the value before the
program even starts.
This is a "compile-time constant." It's even stronger than
final.
void main() {
const double pi = 3.14159;
const String appName = 'My Flutter App';
// const DateTime now = DateTime.now(); // This will cause an ERROR!
// We don't know the time at compile-time.
}
Key Takeaway: In Flutter, you will be encouraged to useconsteverywhere possible. Aconstwidget is a "snapshot" that Flutter doesn't need to rebuild, which gives you a huge performance boost.
Rule of thumb: Always try to use const
first. If you can't, try to use final. Only use
var or an explicit type if the variable *needs* to change
value.
4. The Building Blocks: Common Data Types
Now let's look at the actual "types" of data you can put in your variable boxes.
Numbers (`int` and `double`)
Dart has two types for numbers:
int: Integers, or whole numbers (e.g., 5, -10, 0).-
double: Floating-point numbers, or numbers with a decimal (e.g., 3.14, -0.5, 10.0).
int myAge = 30;
double myScore = 95.5;
int myMoney = 100;
// int myMoney = 100.50; // ERROR: This is a double!
// You can use 'num' if it could be either
num anyNumber = 10;
print(anyNumber); // Output: 10
anyNumber = 10.5;
print(anyNumber); // Output: 10.5
Text (`String`) and String Interpolation
A String is a sequence of text. You create strings using
either single quotes '...' or double quotes
"...".
String name = 'Alice';
String message = "Hello, world!";
The most powerful feature of Dart strings is
interpolation: the ability to insert variables directly
into a string using the $ sign.
String name = 'Alice';
int age = 30;
// The "bad" way (using +)
String greeting = 'Hello, my name is ' + name + ' and I am ' + age.toString() + ' years old.';
print(greeting);
// The "good" way (using interpolation)
String betterGreeting = 'Hello, my name is $name and I am $age years old.';
print(betterGreeting);
If you need to do more than just use a variable name (like an
calculation), you wrap the expression in curly braces ${...}.
int a = 5;
int b = 10;
print('The sum of $a and $b is ${a + b}.');
// Output: The sum of 5 and 10 is 15.
You can also create multi-line strings using triple quotes
'''...''' or """...""".
String longMessage = '''
This is a very long message.
It spans multiple lines.
Isn't that neat?
''';
Truth (`bool`)
The bool type (short for "boolean") has only two possible
values: true or false.
Booleans are the foundation of all logic and decision-making in your app.
"Is the user logged in?" "Is the form valid?" "Is the data done loading?"
The answer is always a bool.
bool isLoggedIn = true;
bool isLoading = false;
if (isLoggedIn) {
print('Welcome back!');
} else {
print('Please log in.');
}
We'll cover if/else logic in a future chapter.
Collections (`List` and `Map`)
These are data types used to store *collections* of other data.
A List is an ordered collection of items (you might know
it as an "array" from other languages).
// A list of strings, specified with
List<String> names = ['Alice', 'Bob', 'Charlie'];
// A list of mixed types (not recommended, but possible)
List shoppingList = ['Apples', 5, 10.99, true];
// Access items by their index (starts at 0)
print(names[0]); // Output: Alice
print(names[1]); // Output: Bob
// Add to a list
names.add('David');
print(names); // Output: [Alice, Bob, Charlie, David]
A Map is a collection of key-value pairs (you might know
it as a "dictionary" or "JSON object").
// A map of user data
Map<String, dynamic> user = {
'name': 'Alice',
'age': 30,
'isStudent': false
};
// Access values by their key
print(user['name']); // Output: Alice
print(user['age']); // Output: 30
// Add a new key-value pair
user['city'] = 'New York';
print(user);
We use Map<String, dynamic> because the keys are
Strings, but the values are of
dynamic (mixed) types.
`dynamic`: The Wildcard (and When to Avoid It)
What if you have a variable that could *truly* be any type? You can use
dynamic.
dynamic myVariable = 'Hello';
print(myVariable);
myVariable = 100;
print(myVariable);
myVariable = true;
print(myVariable);
This looks flexible, but it's dangerous. By using
dynamic, you are telling Dart, "Turn off all your safety
checks!" You lose type inference and the compiler can't help you find
bugs. You might try to call a string function on a number, and your app
will crash.
Rule of thumb: Avoid dynamic at all
costs. Be explicit with your types. The only common exception is when
working with JSON data, as we saw in the Map example.
5. Operators: Getting Things Done
Now that we have data, we need to *do things* with it. That's where operators come in.
Arithmetic Operators
These are for doing math, just like on a calculator.
+ // Addition
- // Subtraction
* // Multiplication
/ // Division
% // Modulo (gets the remainder)
~/ // Integer Division (divides and truncates)
int a = 10;
int b = 3;
print(a + b); // Output: 13
print(a - b); // Output: 7
print(a * b); // Output: 30
print(a / b); // Output: 3.333... (division always results in a double)
print(a % b); // Output: 1 (10 divided by 3 is 3 with a remainder of 1)
print(a ~/ b); // Output: 3 (divides and cuts off the decimal)
Equality and Relational Operators
These are used to compare values. They
always result in a bool (true/false).
== // Equal
!= // Not equal
> // Greater than
< // Less than
>= // Greater than or equal to
<= // Less than or equal to
print(5 == 5); // Output: true
print(5 != 10); // Output: true
print(10 > 3); // Output: true
print('hello' == 'hello'); // Output: true
Very Important: = is for assignment (put
this value in this box). == is for comparison (are these
two values equal?). Don't mix them up!
Logical Operators
These are used to combine multiple bool values.
&& // AND (both must be true)
|| // OR (at least one must be true)
! // NOT (inverts the value)
bool hasKey = true;
bool isDoorLocked = true;
if (hasKey && isDoorLocked) {
print('Door unlocked!');
}
bool hasReservation = false;
bool hasMoney = true;
if (hasReservation || hasMoney) {
print('Welcome to the restaurant!');
}
print(!true); // Output: false
print(!false); // Output: true
Null-Aware Operators (Super Important!)
In modern Dart, all variables are non-nullable by
default. This means a variable must have a value. It cannot be
null (empty).
If you want to allow a variable to be null, you must
explicitly add a ? to its type.
// String name = null; // ERROR! Non-nullable.
String? name = null; // This is allowed. 'name' is a "nullable String".
This "null safety" is amazing, but it can be annoying to work with. Dart gives us special operators to handle it easily.
?? (Null Coalescing Operator): Use this to
provide a "fallback" value if something is null.
String? name; // This is null
// We want to print the name, or 'Guest' if the name is null
String greeting = 'Hello, ${name ?? 'Guest'}';
print(greeting); // Output: Hello, Guest
??= (Null-Aware Assignment): Use this to
assign a value to a variable *only if* that variable is currently null.
String? name; // This is null
name ??= 'Alice'; // 'name' is null, so assign 'Alice' to it.
print(name); // Output: Alice
name ??= 'Bob'; // 'name' is NOT null, so this does nothing.
print(name); // Output: Alice
6. Functions: The Reusable Blocks of Your App
We've already seen main(), which is a function. A
function is simply a named, reusable block of code that
performs a specific task.
Functions are the most important organizational tool in all of programming.
Defining and Calling a Function
You "define" a function to teach the program a new skill. You "call" a function to make it *do* that skill.
// 1. Defining the function
void sayHello() {
print('----------------');
print('Hello from my function!');
print('----------------');
}
void main() {
// 2. Calling the function
sayHello();
sayHello();
}
The "Output" of this will be:
---------------- Hello from my function! ---------------- ---------------- Hello from my function! ----------------
See? We wrote the code once and used it twice. That's the power of functions.
Parameters and Return Values
Functions become *really* useful when you can pass data into them (parameters) and get data out of them (return values).
// This function takes a String 'name' as a parameter.
void greetUser(String name) {
print('Hello, $name! Welcome.');
}
// This function takes two 'int' parameters and returns a new 'int'.
int add(int a, int b) {
int sum = a + b;
return sum;
}
void main() {
greetUser('Alice'); // 'Alice' is the argument
greetUser('Bob'); // 'Bob' is the argument
int mySum = add(5, 10); // Call 'add' and store its return value
print(mySum); // Output: 15
}
Named Parameters: The Flutter Way
This is one of the most important concepts for Flutter. Look at this function:
void buildWidget(String text, double padding, String color) { ... }
If I call it, buildWidget('Submit', 10.0, 'blue')... what
does 10.0 mean? What is 'blue'? It's
confusing.
Dart lets you make your parameters named by
wrapping them in curly braces { }.
// Note the curly braces { }
void buildWidget({String text, double padding, String color}) {
print('Building widget with $text, $padding, and $color');
}
void main() {
// Now when we call it, we use the names!
buildWidget(
text: 'Submit',
color: 'blue',
padding: 10.0
);
// The order doesn't matter!
}
This is infinitely more readable. Flutter's widgets use named parameters almost exclusively.
You can also provide **default values** or mark them as required.
void buildButton({
required String text, // 'required' means you MUST provide this
String color = 'blue', // 'color' has a default value
double padding = 16.0
}) {
print('Building $text button with $color and $padding padding.');
}
void main() {
// I only have to provide 'text'
buildButton(text: 'Submit');
// Output: Building Submit button with blue and 16.0 padding.
// I can override the defaults
buildButton(text: 'Cancel', color: 'red');
// Output: Building Cancel button with red and 16.0 padding.
}
Arrow Syntax: The One-Liner
If your function is very simple and only contains
one line (one return statement), you
can use a "fat arrow" => as a shortcut.
// The "long" way
int add(int a, int b) {
return a + b;
}
// The "short" way using arrow syntax
int addShort(int a, int b) => a + b;
void main() {
print(add(5, 3)); // Output: 8
print(addShort(5, 3)); // Output: 8
}
You'll see this a lot in Flutter code for simple functions.
Conclusion: What You've Learned
Phew! That was a lot of information, but you've just learned the entire foundation of the Dart language. You've gone from a blank page to understanding the core concepts that power every single Flutter app.
Let's recap what you've mastered:
-
Every Dart app starts in the
main()function. -
Variables store data. You can use
varfor type inference, or explicit types likeStringandintfor clarity. -
finalandconstcreate "write-once" variables. You should use them as much as possible. -
The core Data Types are
int,double,String,bool,List, andMap. -
String Interpolation (
'Hello, $name') is the best way to build strings. -
Dart's null safety protects you from errors. You can
use
?,??, and??=to work withnullvalues safely. - Functions are reusable blocks of code.
-
Named Parameters (
{required String text}) are the key to writing clean, readable Flutter code.
Take a break, grab a coffee, and practice these concepts in DartPad. Try to build your own function that takes named parameters and returns a custom string.
In the next chapter, the real fun begins. We'll move from the online DartPad to our own computers. We'll set up our development environment by installing the Flutter SDK, VS Code, and all the tools we need to build and run our a very first Flutter app.
You're building an incredible foundation. Keep it up!

Comments
Post a Comment