Variables, Types, and Inference
Why Programs Need to Remember Things
Every useful program needs to remember information, at least for a little while. A program that greets you remembers your name. A program that scores a game remembers your points. A program that checks a password remembers whether the two passwords matched.
To remember something, a program uses a variable. A variable is a named storage box. You give the box a name, put a value inside it, and later refer to the box by name to get the value back. The name is for you, the human; the box lives in the computer's memory.
Here is a tiny example in Dart, the language this tutorial teaches:
void main() {
String name = 'Ada';
int year = 1815;
print('$name was born in $year.');
}This program creates two variables, name and year, fills them, and prints a sentence using both. Run it and you will see:
Ada was born in 1815.If you have not yet set up Dart on your computer, save the code above in a file called hello.dart and run it with dart run hello.dart in your terminal. A terminal is the text window where you type commands directly to your computer.
Types: Labels on the Boxes
Notice the words String and int before the variable names. Those are types. A type is a label that says what kind of value belongs in the box. Types matter for two reasons:
- They tell the computer how to treat the value. The computer stores the text
'Ada'very differently from the number1815. - They catch mistakes before your program runs. If you try to put text into a box labeled
int, Dart refuses, and you find out immediately instead of suffering a strange failure later.
Dart's most common basic types are:
| Type | What it holds | Examples |
|---|---|---|
| `String` | Text, wrapped in quotes | `'Ada'`, `"hello"` |
| `int` | Whole numbers | `1815`, `-7`, `0` |
| `double` | Numbers with a decimal point | `9.5`, `-0.25` |
| `bool` | Truth values | `true`, `false` |
| `List` | An ordered collection of values | `['Ada', 'Alan']` |
A String holding numbers as text, like '1815', is not the same as the int value 1815. Text looks like a number but cannot do math. Keeping these categories separate is what makes types useful.
Inference: Letting Dart Figure Out the Type
Writing the type every time can feel like extra work. Dart agrees, so it offers type inference. Inference means Dart looks at the value you are putting into the box and works out the type by itself.
The keyword var says "make a variable, and you, Dart, decide the type":
void main() {
var name = 'Ada'; // Dart infers this is a String
var year = 1815; // Dart infers this is an int
var score = 9.5; // Dart infers this is a double
var active = true; // Dart infers this is a bool
print('$name, $year, $score, $active');
}Important point: inference is not the same as "no type." The variable name still has the type String. Dart simply wrote the label for you. Once a type is inferred, it is locked in. This will not compile:
void main() {
var year = 1815; // inferred as int
year = 'next year'; // error: cannot assign a String to an int
}So when should you write the type yourself, and when should you use var? A common rule among Dart programmers:
- Use
varwhen the value on the right makes the type obvious, as in the examples above. - Write the type when it is not obvious, or when you want the reader to see it at a glance, such as
double average = sum / count;.
Both styles produce equally safe code. This is mostly a readability choice.
Choosing Variables That Never Change: final and const
Sometimes a variable should be filled once and never changed again, like a person's birthday. Dart has two keywords for this:
finalmeans "set this value once, at run time, and never change it."constmeans "this value is fixed forever, known before the program even runs."
void main() {
final greeting = 'Hello, Dart!';
const secondsPerHour = 3600;
print(greeting);
print(secondsPerHour);
}If you try to assign to a final variable a second time, Dart stops you. Using final by default is a good habit: it tells anyone reading your code that this value will not wander off, and it lets Dart check that promise.
The difference between final and const is subtle but real. Use const when the value is a fixed, simple thing that could be written directly in the source code, like 3600. Use final when the value is computed while the program runs, such as a timestamp or the result of a function call.
callout tip When in doubt, start with final. If Dart tells you the value is not a constant, switch to final fully or keep var if the value will change later. endcallout
String Interpolation: Mixing Text and Values
You saw lines like print('$name was born in $year.'). This is string interpolation, a feature that lets you drop variable values directly into text. Put a $ before a variable name inside a string, and Dart inserts that variable's value. For longer expressions, wrap them in curly braces:
void main() {
var a = 6;
var b = 7;
print('The answer is ${a * b}.'); // prints: The answer is 42.
}Without interpolation you would have to glue pieces of text together by hand. Interpolation is shorter, clearer, and harder to get wrong.
A Small Worked Program
Here is a program that puts everything together: typed variables, inferred ones, a final value, and interpolation.
void main() {
String firstName = 'Ada'; // explicit type
var birthYear = 1815; // inferred as int
final currentYear = 2025; // will never change
var age = currentYear - birthYear;
bool wasProlific = true;
print('$firstName lived about $age years ago.');
print('Prolific writer: $wasProlific');
}Output:
Ada lived about 210 years ago.
Prolific writer: trueRead the program line by line and check that each variable makes sense to you. age is computed from two other variables, which is one of the most common things programs do.
diagram mermaid caption: A variable is a labeled box: the name is outside, the value is inside, and the type describes what fits. alt: A diagram showing three boxes. The first box is labeled name and holds the text Ada. The second box is labeled year and holds the number 1815. The third box is labeled score and holds the number 9.5. flowchart LR A["name : String"] -->|"holds"| A1["'Ada'"] B["year : int"] -->|"holds"| B1["1815"] C["score : double"] -->|"holds"| C1["9.5"] end
Common First Mistakes
- Mixing up quotes and apostrophes. In Dart,
'Ada'and"Ada"are both fine, but'Ada"is not. Keep the opening and closing marks the same. - Doing math on text.
'1815' + 10is an error, not1825. Convert first if you need to. - Changing a type after inference. Remember,
var x = 5;makesxanintforever.
exercise Q: What type does Dart infer for the variable in var isOpen = false;, and what happens if you later write isOpen = 'yes';? A: Dart infers bool, because false is a truth value. The later assignment fails: you cannot put a String into a variable whose type is bool, and Dart reports this as an error before the program runs. end
exercise Q: Rewrite print('Total: ' + '3'); using string interpolation with an int variable that holds 3, and say why the new version is better. A: With var total = 3; you can write print('Total: $total');. This is better because total is a real number the program can do math with, and the same pattern works for any variable instead of hand-building the text. end
estimate minutes: 45 end
Spotted a mistake, or code that does not work?