Glossary
The following are definitions of terms used across the Dart documentation.
Application package
A Dart package that contains a runnable application.
An application package is a Dart package that contains a program or app with a main entrypoint. Meant to be run directly, either on the command line, in a browser, or by another embedder, such as provided by Flutter.
Application packages can have dependencies on other packages, but are never depended on themselves. Unlike regular packages, they are not intended to be shared.
Application packages should check their lockfiles into source control, so that everyone working on the application and every location the application is deployed has a consistent set of dependencies.
Related docs and resources
Assist
An automated, local code edit targeted at making common improvements to code.
An assist is an automated, local code edit targeted at making common
improvements to code.
Examples of assists include converting
switch
statements to
switch
expressions, reversing the
then
and
else
blocks in an
if
statement,
and inserting widgets into a widget structure.
Related docs and resources
Bottom type
A type that has no values and is a subtype of all other types.
The bottom type in Dart is the type that has no values and is considered a subtype of every other type.
In Dart, the bottom type is represented by the Never
type.
This means a value of type
Never
can be used anywhere,
because such a value can never actually exist.
It's most often used as the
return type
of functions to
indicate they
never return, such as for those that
throw exceptions or loop forever.
For example, the following
fail
function always throws an exception,
so it's declared with a return type of
Never
to
indicate that it never returns:
Never fail(String message) {
throw Exception(message);
}
void main() {
String result = fail('Oops'); // OK: Never is a subtype of String.
}
Since fail
never returns, assigning it to a String
is allowed.
Related docs and resources
Code asset
Compiled native code that is bundled with a Dart app using a build hook
and can be used through
dart:ffi
.
A
code asset
is compiled code that isn't written in Dart but
can be packaged and used by a Dart application.
Examples include shared libraries (.so
,
.dll
,
.dylib
) built
in languages like C, C++, or Rust.
Code assets can be bundled with a Dart package using a build hook. Dart code can call into these assets using FFI.
Historically, code assets were also referred to as native assets or native code assets.
Code assets are useful for:
- Integrating with existing native libraries.
- Accessing system capabilities not directly exposed in Dart.
- Sharing performance-critical functionality across platforms.
For example, a Dart application could include a native
.so
library
that exposes specific functions, and call those functions from Dart.
Related docs and resources
Combinator
A keyword clause that limits or modifies what's imported or exported.
In Dart, a
combinator
is a clause that
follows an
import
or
export
directive to limit or modify
the set of names brought into scope.
Dart supports two types of combinators:
show
— explicitly includes specific names.hide
— excludes specific names.
Combinators help control namespace pollution and avoid conflicts when multiple libraries define symbols with the same name.
Example using show
:
import 'dart:math' show pi, sqrt;
void main() {
print(pi); // Accessible
print(sqrt(9)); // Accessible
// print(Random()); // Error: Random is not imported.
}
Example using hide
:
import 'dart:math' hide pi;
void main() {
// print(pi); // Error: pi is hidden.
print(Random()); // Accessible
}
Related docs and resources
Constant context
A region of code where the const keyword is implied and everything within that region must be a constant.
A
constant context
is a region of code in which it
isn't necessary to include the
const
keyword because it's implied by
the fact that everything in that region is required to be a constant.
The following locations are constant contexts:
-
Everything inside a list, map or set literal that's prefixed by the
const
keyword. For example:dartvar l = const [/*constant context*/];
-
The arguments inside an invocation of a constant constructor. For example:
dartvar p = const Point(/*constant context*/);
-
The initializer for a variable that's prefixed by the
const
keyword. For example:dartconst v = /*constant context*/;
Annotations.
-
The expression in a
case
clause. For example:dartvoid f(int e) { switch (e) { case /*constant context*/: break; } }
Related docs and resources
Context type
The type that the surrounding code expects from an expression.
The context type is the type that the surrounding code expects from an expression, such as a variable type, a parameter type, or a return type.
Dart uses the context type to interpret and infer meaning from expressions, including:
-
Type inference ("downwards inference"):
dartList<int> list = [];
The context type
List<int>
lets the compiler infer the list type as<int>[]
. -
Implicit downcast:
dartString asString(dynamic value) => value;
The return context is
String
, so Dart inserts an implicit downcast. -
Literal interpretation:
dartdouble d = 0;
The context type
double
makes0
behave like0.0
. -
Static access shorthand (dot shorthand):
dartint x = .parse(input);
The context type is
int
, so.parse
resolves toint.parse(input)
.
Some expressions have no context type, including:
-
When used as statements:
Expressions likeset.remove(value);
are used only for their effect, not their value, so no type is expected. -
When the context type is inferred from the expression:
For example, invar list = [1];
, the list literal has no context type. Dart infersList<int>
from the contents and assigns that type to the variable.
Related docs and resources
Dart SDK constraint
The versions of Dart that a package supports.
The range of Dart SDK versions that a package itself declares it supports.
An SDK constraint is specified using normal
version constraint
syntax,
but in a special
environment
section
in the pubspec.
Related docs and resources
Definite assignment
The determination of whether a variable has definitely been assigned a value before it's used.
Definite assignment analysis is the process of determining, for each local variable at each point in the code, which of the following is true:
- The variable has definitely been assigned a value ( definitely assigned ).
- The variable has definitely not been assigned a value ( definitely unassigned ).
- The variable might or might not have been assigned a value, depending on the execution path taken to arrive at that point.
Definite assignment analysis helps find problems in code, such as places where a variable that might not have been assigned a value is being referenced, or places where a variable that can only be assigned a value one time is being assigned after it might already have been assigned a value.
For example, in the following code the variable
s
is
definitely unassigned when it's passed as an argument to
print
:
void f() {
String s;
print(s);
}
But in the following code, the variable s
is definitely assigned:
void f(String name) {
String s = 'Hello $name!';
print(s);
}
Definite assignment analysis can even tell whether
a variable is definitely assigned (or unassigned) when
there are multiple possible execution paths.
In the following code the
print
function is called if
execution goes through either the true or the false branch of the
if
statement, but because
s
is assigned no matter which branch is taken,
it's definitely assigned before it's passed to
print
:
void f(String name, bool casual) {
String s;
if (casual) {
s = 'Hi $name!';
} else {
s = 'Hello $name!';
}
print(s);
}
In flow analysis, the end of the
if
statement is referred to
as a
join—a place where two or more execution paths merge back together.
Where there's a join, the analysis says that
a variable is definitely assigned if it's definitely assigned along
all of the paths that are merging, and definitely unassigned if
it's definitely unassigned along all of the paths.
Sometimes a variable is assigned a value on one path but not on another,
in which case the variable might or might not have been assigned a value.
In the following example, the true branch of the
if
statement might or
might not be executed, so the variable might or might be assigned a value:
void f(String name, bool casual) {
String s;
if (casual) {
s = 'Hi $name!';
}
print(s);
}
The same is true if there is a false branch that
doesn't assign a value to
s
.
The analysis of loops is a little more complicated,
but it follows the same basic reasoning.
For example, the condition in a
while
loop is always executed,
but the body might or might not be. So just like an
if
statement,
there's a join at the end of the
while
statement between
the path in which the condition is
true
and
the path in which the condition is
false
.
Related docs and resources
Dependency
A Dart package that a package relies on.
A dependency is any other Dart package that a package relies on. If your package wants to import code from some other package, that package must be a dependency of yours first. Dependencies are specified in your package's pubspec file with the syntax described in Package dependencies.
To view the dependencies used by a package, use
pub deps
.
Related docs and resources
Dependency source
A kind of place that pub can get packages from.
A type of repository or location that pub can retrieve packages from. A source isn't a specific place like the pub.dev site or a specific git URL. Each source describes a general procedure for accessing a package.
As an example, git is one of the supported dependency source. The git source knows how to download packages given a git URL. Several different supported sources are available.
Related docs and resources
Entrypoint
A Dart library that is directly invoked by a Dart implementation.
In the general context of Dart, an
entrypoint
is
a Dart library that is directly invoked by a Dart implementation.
For example, when you pass a Dart library as a command-line argument to
the standalone Dart VM, that library is the entrypoint.
In other words, it's usually the
.dart
file that contains
main()
.
In the context of pub, an entrypoint package or root package is the root of a dependency graph. It will usually be an application. When you run your app, it's the entrypoint package. Every other package it depends on will not be an entrypoint in that context.
A package can be an entrypoint in some contexts and not in others.
Say your app uses a package
A
.
When you run your app,
A
is not the entrypoint package.
However, if you go over to
A
and execute its tests, in that context,
it
is
the entrypoint since your app isn't involved.
Related docs and resources
Entrypoint directory
A directory that contains Dart entrypoints.
An entrypoint directory is a directory inside your Dart package that is allowed to contain Dart entrypoints.
Pub has a list of these directories:
benchmark
,
bin
,
example
,
test
,
tool
, and
web
(and
lib
, for
Flutter apps).
Any subdirectories of those (except
bin
) can also contain entrypoints.
Related docs and resources
Function
An umbrella term to refer to top-level functions, local functions, static methods, and instance methods.
Related docs and resources
Immediate dependency
A dependency that a Dart package directly uses.
An immediate dependency is a
dependency
that a
package directly uses and declares itself.
The dependencies you list in your
pubspec.yaml
file are
your package's immediate dependencies.
All other dependencies are
transitive dependencies.
Related docs and resources
Immutable
An object whose state, including all nested values, can't be changed after it is created.
An immutable object is one whose state can't be modified after it is created.
When an object is immutable, all of its fields must be
final
(can't be reassigned), and
the values of those fields must themselves be immutable (can't be mutated).
This helps ensure consistency and enables safer use in concurrent or reactive code.
In Dart, a class is immutable if you:
- Declare all fields as final, so they can't be reassigned.
- Ensure the field values themselves are immutable.
-
Optionally, use the
@immutable
annotation from the meta package. This lets the analyzer warn you if any field is not final or refers to a mutable type.
Additionally, all Dart const values are immutable. For example,
const [1, 2, 3]
creates an immutable list. If a class has a
const
(non-factory) constructor, then
all of its fields must be final.
Example:
import 'package:meta/meta.dart';
@immutable
class User {
final String name;
final int age;
const User(this.name, this.age);
}
In the proceeding example, once created, you can't modify the
User
instance.
You must create a new one to change any data.
Related docs and resources
Irrefutable pattern
A pattern that always matches.
Irrefutable patterns are patterns that always match. Irrefutable patterns are the only patterns that can appear in irrefutable contexts: the declaration and assignment pattern contexts.
Related docs and resources
Late
A keyword that enables deferred initialization of variables and is typically used with non-nullable variables.
The
late
keyword in Dart is used to indicate that a variable
will be initialized later, after its declaration, but before it's used.
This helps avoid the need to make a variable nullable (?
) when you
know it will definitely receive a value, just not immediately.
Using
late
defers initialization, allowing you to write more
flexible and readable code, especially when dealing with dependencies
or complex setup.
For example:
late String description;
void setup() {
description = 'This will be initialized before use.';
}
Be careful with late variables that are part of a public API.
If a client accesses the variable before it's initialized,
they will encounter a
LateInitializationError
, which provides
little context. In such cases, consider using a
private nullable variable with a public getter that throws a
descriptive error (e.g.,
StateError
) if accessed too early as
this can offer clearer feedback to API users, despite the added
complexity.
You can also use
late final
when the variable should only be set once.
This is useful in scenarios where the value is not available at object
construction time, such as cyclic dependencies in object graphs.
Example:
class LinkedQueue<T> {
late final QueueLink<T> _head;
LinkedQueue() {
_head = QueueLink<T>._head(owner: this); // Cyclic reference between objects
}
}
Be cautious: if a late variable is accessed before it's initialized or never initialized at all, it will cause a runtime error.
Related docs and resources
Library
A single compilation unit in Dart, made up of a primary Dart file and its parts.
A Dart
library
is a single compilation unit in Dart,
made up of a primary
.dart
file and any optional number of
parts.
Libraries have their own private scope.
Related docs and resources
Lockfile
A file named pubspec.lock that specifies the versions of each dependency.
A file named
pubspec.lock
that specifies the
concrete versions and other identifying information for every
immediate
and
transitive
dependency a package relies on.
Unlike the pubspec, which only lists immediate dependencies and allows version ranges, the lockfile comprehensively pins down the entire dependency graph to specific versions of packages. A lockfile ensures that you can recreate the exact configuration of packages used by an application.
The lockfile is generated automatically for you by pub when you run
pub get
,
pub upgrade
, or
pub downgrade
.
Pub includes a
content hash
for each dependency
to check against during future resolutions.
If your package is an application package, you will typically check this into source control. For regular (library) packages, you usually won't.
Related docs and resources
Mixin application
A class created when a mixin is applied to a class.
A mixin application is the class created when a mixin is applied to a class. For example, consider the following declarations:
class A {}
mixin M {}
class B extends A with M {}
The class
B
is a subclass of the mixin application of
M
to
A
,
sometimes nomenclated as
A+M
. The class
A+M
is a subclass of
A
and
has members that are copied from
M
.
You can give an actual name to a mixin application by defining it as:
class A {}
mixin M {}
class A_M = A with M;
Given this declaration of
A_M
, the following declaration of
B
is
equivalent to the declaration of
B
in the original example:
class B extends A_M {}
Related docs and resources
Override inference
How missing types in a method declaration are inferred.
Override inference is the process by which any missing types in a method declaration are inferred based on the corresponding types from the method or methods that it overrides.
If a candidate method (the method that's missing type information) overrides a single inherited method, then the corresponding types from the overridden method are inferred. For example, consider the following code:
class A {
int m(String s) => 0;
}
class B extends A {
@override
m(s) => 1;
}
The declaration of
m
in
B
is a candidate because
it's missing both the return type and the parameter type.
Because it overrides a single method (the method
m
in
A
),
the types from the overridden method will be used to infer
the missing types and it will be as if the method in
B
had been
declared as
int m(String s) => 1;
.
If a candidate method overrides multiple methods, and the function type one of those overridden methods, Ms, is a supertype of the function types of all of the other overridden methods, then Ms is used to infer the missing types. For example, consider the following code:
class A {
int m(num n) => 0;
}
class B {
num m(int i) => 0;
}
class C implements A, B {
@override
m(n) => 1;
}
The declaration of
m
in
C
is a candidate for override inference because
it's missing both the return type and the parameter type.
It overrides both
m
in
A
and
m
in
B
, so the compiler needs to
choose one of them from which the missing types can be inferred.
But because the function type of
m
in
A
(int Function(num)
) is
a supertype of the function type of
m
in
B
(num Function(int)
),
the function in
A
is used to infer the missing types. The result is
the same as declaring the method in
C
as
int m(num n) => 1;
.
It is an error if none of the overridden methods have a function type that is a supertype of all the other overridden methods.
Related docs and resources
Package
A directory with a collection of Dart libraries, resources, and a pubspec.yaml file describing them.
A Dart
package
is a collection of Dart
libraries
and resources in
a directory, with a
pubspec.yaml
file in the root of that directory.
Packages can have
dependencies
on other packages
and
can be dependencies themselves.
A package's
/lib
directory contains the
public libraries
that
other packages can import and use.
They can also include scripts to be run directly.
A package that is not intended to be depended on by
other packages is an
application package.
Shared packages are
published
to pub.dev,
but you can also have non-published packages.
Don't check the lockfile of a package into source control, since libraries should support a range of dependency versions. The version constraints of a package's immediate dependencies should be as wide as possible while still ensuring that the dependencies will be compatible with the versions that were tested against.
Since
semantic versioning
requires that
libraries increment their major version numbers for
any backwards incompatible changes, packages will usually
require their dependencies' versions to be greater than or equal to
the versions that were tested and less than the next major version.
So if your library depended on the (fictional)
transmogrify
package and
you tested it at version
1.2.1
, your version constraint would be
^1.2.1
.
Related docs and resources
Package uploader
A pub.dev user who has administrative permissions for a package.
A package uploader is someone who has administrative permissions for a package. A package uploader can upload new versions of the package, and they can also add and remove other uploaders for that package.
If a package has a verified publisher, then all members of the publisher can upload the package.
Related docs and resources
Part file
A Dart source file that contains a part of
directive.
A part file is a Dart source file that contains a
part of
directive
and is included in a library using the
part
directive.
Related docs and resources
Potentially non-nullable
A type that is either non-nullable explicitly or due to being a type parameter.
A type is potentially non-nullable if it's either explicitly non-nullable or if it's a type parameter.
A type is explicitly non-nullable if it is a
type name that isn't followed by a question mark (?
).
Note that there are a few types that are always nullable, such as
Null
and
dynamic
, and that
FutureOr
is only non-nullable if
it isn't followed by a question mark
and
the type argument is non-nullable (such as
FutureOr<String>
).
Type parameters are potentially non-nullable because the actual
runtime type (the type specified as a type argument) might be non-nullable.
For example, given a declaration of
class C<T> {}
,
the type
C
could be used with a non-nullable type argument as in
C<int>
.
Related docs and resources
Pub content hash
SHA256 hashes maintained by pub.dev to validate package integrity.
The pub.dev repository maintains a SHA256 content hash of each version of each package it hosts. Pub clients use this hash to validate the integrity of downloaded packages, and protect against changes on the source repository.
When
dart pub get
downloads a package,
it computes the hash of the downloaded archive.
The hash of each hosted dependency is stored with the
resolution
in the
lockfile.
The pub client uses this content hash to verify that
running
dart pub get
again using the same lockfile,
potentially on a different computer, uses exactly the same packages.
If the locked hash doesn't match what's currently in the pub cache, pub redownloads the archive. If it still doesn't match, the lockfile updates and a warning is printed.
To make a discrepancy become an error instead of a warning,
use the
--enforce-lockfile
option for
dart pub get
.
With this option, if pub can't find package archives with the same hashes,
dependency resolution fails and the lockfile isn't updated.
Related docs and resources
Pub system cache
A directory where pub stores downloaded remote packages.
When pub gets a remote package,
it downloads it into a single
pub system cache
directory.
On macOS and Linux, this directory defaults to
~/.pub-cache
.
On Windows, the directory defaults to
%LOCALAPPDATA%\Pub\Cache
,
though its exact location might vary depending on the Windows version.
You can specify a different location using the
PUB_CACHE
environment variable.
Once packages are in the system cache,
pub creates a
package_config.json
file that maps each package
used by your application to the corresponding package in the cache.
You only have to download a given version of a package once
and can then reuse it in as many packages as you would like.
If you specify the
--offline
flag to use cached packages,
you can delete and regenerate your
package_config.json
files without having to access the network.
Related docs and resources
Pub workspace
A collection of packages that are developed together with a shared resolution of their dependency constraints.
A pub workspace associated a collection of local packages that are treated as a single unit during development, enabling shared resolution of their dependency constraints. Useful for developing in a monorepo.
The packages have shared
pubspec.lock
and
.dart_tool/package_config.json
files in the workspace root directory.
Related docs and resources
Public library
A library that is located in a package's
lib
directory but
not inside the
lib/src
directory.
A public library is a library that is located inside the package's
lib
directory but not inside the
lib/src
directory.
Related docs and resources
Quick fix
An automated, local code edit targeted at fixing the issue reported by a specific diagnostic.
Related docs and resources
Refactor
A code edit targeted at modifications that are either non-local or that require user interaction.
A refactor is a code edit targeted at modifications that are either non-local or that require user interaction. Examples of refactors include renaming, removing, or extracting code.
Related docs and resources
Refutable pattern
A pattern that can be tested against a value.
A refutable pattern is a pattern that can be tested against a value to determine if the pattern matches the value. If not, the pattern refutes, or denies, the match. Refutable patterns appear in matching contexts.
Related docs and resources
Shadowing
When a local declaration hides another with the same name.
Shadowing occurs when a local declaration, such as a variable or parameter, uses the same name as an existing declaration in an outer scope, making the outer one inaccessible within the inner scope.
While valid in Dart, shadowing can lead to confusing code or unintended behavior. As a result, it's generally discouraged unless used deliberately to improve the clarity of your code.
Example
#
In this example, the local
message
variable inside
the
printMessage
function
shadows
the top-level
message
variable:
final message = 'Global';
void printMessage() {
final message = 'Local'; // Shadows the global `message` variable.
print(message); // Prints: Local
}
void main() {
printMessage();
print(message); // Prints: Global
}
Shadowing can also occur in nested blocks:
void main() {
final value = 10;
if (true) {
final value = 20; // Shadows the outer `value` variable.
print(value); // Prints: 20
}
print(value); // Prints: 10
}
Subclass
A class that inherits the implementation of another class.
A
subclass
is a class that inherits the implementation of another class by
using the
extends
keyword, or by
mixin application.
// A is a subclass of B; B is the superclass of A.
class A extends B {}
// B1 has the superclass `A with M`, which has the superclass A.
class B1 extends A with M {}
A subclass relation also implies an associated
subtype
relation.
For example,
class A
implicitly defines an associated type
A
which instances of the class
A
inhabit.
So,
class A extends B
declares not just that the class
A
is a subclass of
B
, but also establishes that the
type
A
is a
subtype
of the type
B
.
Subclass relations are a subset of subtype relations.
When the documentation says "S
must be a subtype of
T
",
it's fine for
S
to be a subclass of
T
.
However, the converse is not true: not all subtypes are subclasses.
Related docs and resources
Subtype
A type that can be used wherever a value of its supertype is expected.
A
subtype
relation is where a value of a certain type is substitutable
where the value of another type, the supertype, is expected.
For example, if
S
is a subtype of
T
,
then you can substitute a value of type
S
where a value of type
T
is expected.
A subtype supports all of the operations of its supertype (and possibly some extra operations). In practice, this means you can assign the value of a subtype to any location expecting the supertype, and all of the methods of the supertype are available on the subtype.
This is true at least statically. A specific API might not allow the substitution at run time, depending on its operations.
Some subtype relations are based on the structure of the type,
like with nullable types (for example,
int
is a subtype of
int?
)
and function types
(for example,
String Function()
is a subtype of
void Function()
).
Subtypes can also be introduced for classes by implementation or inheritance (direct or indirect):
// A is a subtype of B, but NOT a subclass of B.
class A implements B {}
// C is a subtype AND a subclass of D.
class C extends D {}
Related docs and resources
Transitive dependency
A dependency that a package indirectly uses because one of its dependencies requires it.
A transitive dependency is a dependency that a package indirectly uses because one of its dependencies, or their dependencies, requires it.
If your package depends on A, which in turn depends on B which depends on C, then A is an immediate dependency and B and C are transitive ones.
Related docs and resources
Type alias
A user-defined name for an existing type.
A type alias is an alternative name that refers to another type.
They can be used to simplify complex type definitions, improve readability, or create semantic meaning in code.
Dart supports defining type aliases using the
typedef
keyword.
You can alias functions, classes, and even generic types.
Examples
#Function type alias
#typedef StringTransformer = String Function(String);
void printTransformed(String input, StringTransformer transformer) {
print(transformer(input));
}
void main() {
printTransformed('hello', (str) => str.toUpperCase()); // Output: HELLO
}
Class alias
#class HttpClient {}
typedef Client = HttpClient;
Client client = HttpClient();
Type aliases don't create new types, they just provide alternate names.
Related docs and resources
Variance and variance positions
How changing a type argument of a type affects the relationship between the original type and the resulting one.
In Dart, changing the type argument of a type declaration (like a class) or function return type, changes the overall type relationship in the same direction (covariant).
However, changing the type of a function's parameter types, changes the overall type relationship in the opposite direction (contravariant).
A type parameter of a class (or other type declaration, like a mixin) is said to be covariant when the type as a whole "co-varies" with the actual type argument. In other words, if the type argument is replaced by a subtype then the type as a whole is also a subtype.
For example, the type parameter of the class
List
is covariant because
list types co-vary with their type argument:
List<int>
is a subtype of
List<Object>
because
int
is a subtype of
Object
.
In Dart, all type parameters of all class, mixin, mixin class, and enum declarations are covariant.
However, function types are different:
A function type is covariant in its return type, but
the opposite (known as
contravariant) in its parameter types.
For example, the type
int Function(int)
is a
subtype of the type
Object Function(int)
, but it is a
supertype of
int Function(Object)
.
This makes sense if you consider their
substitutability.
If you call a function with a static type of
int Function(int)
,
that function can actually be of type
int Function(Object)
at runtime.
Based on the static type, you expect to be able to pass an
int
to it.
That will be fine since the function actually accepts any
Object
,
and this includes every object of type
int
.
Similarly, the returned result will be of type
int
,
which is also what you expect based on the static type.
Hence, int Function(Object)
is a subtype of int Function(int)
.
Note that everything is turned upside-down for parameter types.
In particular, this subtype relation among function types requires that
the
opposite
subtype relation exists for the parameter type.
For example,
void Function(Object)
is a subtype of
void Function(int)
because
int
is a subtype of
Object
.
With a more complex type like
List<void Function(int)>
,
you have to consider the
positions
in the type.
To accomplish this, turn one of the parts of the type into a placeholder,
and then consider what happens to the type when
different types are placed in that position.
For example, consider
List<void Function(_)>
as a template for
a type where you can put different types in place of the placeholder
_
.
This type is contravariant in the position where that placeholder occurs.
The following illustrates this by substituting
Object
and
int
for
_
.
List<void Function(Object)>
is a subtype of
List<void Function(int)>
because
void Function(Object)
is a subtype of
void Function(int)
because
void
is a subtype of
void
(the return types) and
int
is a subtype of
Object
(the parameter types, in the opposite order).
Hence, the type at
_
varies in the opposite direction of
the type
List<void Function(_)>
as a whole, and this
'opposite direction' by definition makes it a
contravariant position.
A
covariant position
is defined similarly.
For example,
_
is at a covariant position in the type
List<_>
,
and
_
is also at a covariant position in the type
_ Function(int)
.
There is yet another kind of position known as invariant, but it occurs much more rarely so the details are omitted here.
In practice, it's often sufficient to know that the type arguments of a class, mixin, etc. are in a covariant position, and so is the return type of a function type, but the parameter types are in a contravariant position.
Related docs and resources
Verified publisher
A package publisher on the pub.dev site whose identity has been verified by pub.dev.
A verified publisher is a collection of one or more users who are identified with a unique domain name. The ownership of the domain name is verified by pub.dev, such as for the dart.dev publisher on pub.dev by the Dart team.
Related docs and resources
Version constraint
A constraint associated with each dependency that specifies which versions a package is expected to work with.
A
version constraint
is a specified range of compatible versions
of a
dependency
for a package.
This can be a single version (0.3.0
) or a range of versions (^1.2.1
).
While
any
is also allowed, for performance reasons it's not recommended.
Library packages should always specify version constraints for each of their non-dev dependencies. Application packages, on the other hand, can allow any version of their dependencies, since they use the lockfile to manage their dependency versions.
Related docs and resources
Wildcard
A symbol (_
) used instead of a variable name to
indicate an unused value in patterns and other contexts.
A wildcard is the underscore character (_
) used to
ignore values or indicate that a value is intentionally unused.
It's often used in patterns, destructuring, and switch expressions to
match any value without binding it to a name.
Wildcards help make the code more intentional by clearly marking values that aren't needed in a specific context.
Example:
// Ignoring the value in a for-each loop.
var names = ['Alice', 'Bob', 'Charlie'];
for (var _ in names) {
print('Someone is here!');
}
The wildcard pattern is particularly useful when:
- You only need certain parts of a destructured value.
- You want to explicitly show some values are being ignored.
- You need a catch-all case in pattern matching.
Related docs and resources
Zone
A mechanism to customize the behavior of asynchronous code without modifying the asynchronous code itself.
A zone is an execution context that allows you to run code with customized behavior for asynchronous events such as timers, microtasks, and uncaught errors.
Zones are useful for:
- Logging
- Error tracking
- Maintaining request-specific state across async gaps (for example, in server apps)
- Testing and debugging async behavior
Zones provide a way to track and influence asynchronous execution without requiring the asynchronous code to be aware of it.
You can create a new zone using
runZoned
(or
runZonedGuarded
)
and override zone-specific behavior such as error handling and timers.
Even
print
can be overridden, although it's not asynchronous and just
included for convenience.
Example:
import 'dart:async';
void main() {
runZonedGuarded(() {
Future.delayed(Duration(seconds: 1), () {
throw 'Zone caught this error!';
});
}, (error, stackTrace) {
print('Caught error: $error');
});
}
In the preceding example, the uncaught error inside the async callback is intercepted by the custom zone.
Related docs and resources
Unless stated otherwise, the documentation on this site reflects Dart 3.9.2. Report an issue.