Dart Scope
last modified June 4, 2025
In Dart, scope defines the visibility and lifetime of variables and functions, determining where in the program an identifier can be accessed.
Dart follows a lexical scoping model, meaning that the visibility of variables is determined by the code's structure rather than execution flow. A variable remains accessible from its point of declaration until the end of its enclosing block, ensuring predictable behavior in nested functions and closures.
The scope of a variable is determined by where it is declared. Dart supports several types of scopes:
- Global Scope: Variables declared outside any function or class.
- Local Scope: Variables declared within a function or block.
- Function Parameter Scope: Parameters of a function are local to that function.
- Block Scope: Variables declared within a block (e.g., inside an if statement).
- Lexical Closures: Functions can capture variables from their surrounding scope.
Shadowing occurs when a local variable has the same name as a global variable or a variable in an outer scope. The local variable takes precedence within its scope, effectively hiding the outer variable.
Global Scope
Variables declared outside any function or class have global scope. They can be accessed from anywhere in the program.
// Global variable var globalVar = 'I am global'; void main() { print(globalVar); // Accessible here someFunction(); } void someFunction() { print(globalVar); // Also accessible here }
The globalVar is declared outside any function, making it globally accessible.
Both main
and someFunction
can access and use this
variable.
$ dart main.dart I am global I am global
Local Scope
Variables declared inside a function or block have local scope. They are only accessible within that function or block.
void main() { var localVar = 'I am local'; print(localVar); // Works fine if (true) { var blockVar = 'I am block scoped'; print(blockVar); // Works here } // print(blockVar); // Error: Undefined name 'blockVar' } void anotherFunction() { // print(localVar); // Error: Undefined name 'localVar' }
localVar is only accessible within main(), while blockVar is only accessible within the if block. Attempting to access them outside their scope causes errors.
$ dart main.dart I am local I am block scoped
Function Parameter Scope
Function parameters have scope limited to the function body. They behave like local variables but are initialized with the passed arguments.
void greet(String name) { print('Hello, $name!'); // name is accessible here } void main() { greet('Alice'); // print(name); // Error: Undefined name 'name' }
The name parameter is only accessible within the greet function. Trying to use it outside the function results in an error, just like with local variables.
$ dart main.dart Hello, Alice!
Shadowing Variables
When a local variable has the same name as a variable in an outer scope, it shadows the outer variable. The inner variable takes precedence.
var shadowed = 'Global'; void main() { var shadowed = 'Local'; print(shadowed); // Prints local if (true) { var shadowed = 'Block'; print(shadowed); // Prints block } print(shadowed); // Prints local again }
Each new declaration of shadowed creates a new variable that hides the previous one in that scope. The original global variable remains unchanged but inaccessible.
$ dart main.dart Local Block Local
Lexical Closures
Dart functions can close over variables in their lexical scope, creating closures. The function retains access to these variables even when executed outside their scope.
Function makeCounter() { var count = 0; return () { count++; return count; }; } void main() { var counter = makeCounter(); print(counter()); // 1 print(counter()); // 2 print(counter()); // 3 }
The anonymous function returned by makeCounter
closes over the
count
variable. Each call to counter
accesses and
modifies this same count
variable, despite it being local to
makeCounter
.
$ dart main.dart 1 2 3
Best Practices
- Minimize globals: Use local variables whenever possible.
- Clear naming: Avoid shadowing with descriptive names.
- Small scopes: Declare variables in the smallest needed scope.
- Closure awareness: Be mindful of what variables closures capture.
Source
This tutorial covered Dart's scoping rules with practical examples demonstrating how variable visibility works in different contexts.
Author
List all Dart tutorials.