CINXE.COM
Effective Dart: Usage | Dart
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="x-ua-compatible" content="ie=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><script>!function(e,t,a,n){e[n]=e[n]||[],e[n].push({"gtm.start":(new Date).getTime(),event:"gtm.js"});var g=t.getElementsByTagName(a)[0],m=t.createElement(a);m.async=!0,m.src="https://www.googletagmanager.com/gtm.js?id=GTM-5VSZM5J",g.parentNode.insertBefore(m,g)}(window,document,"script","dataLayer")</script><meta name="description" content="Guidelines for using language features to write maintainable code."><title>Effective Dart: Usage | Dart</title><link rel="icon" sizes="64x64" href="/assets/img/logo/dart-64.png" eleventy:ignore><link href="/assets/img/touch-icon-iphone.png" rel="apple-touch-icon" eleventy:ignore><link href="/assets/img/touch-icon-ipad.png" rel="apple-touch-icon" sizes="152x152" eleventy:ignore><link href="/assets/img/touch-icon-iphone-retina.png" rel="apple-touch-icon" sizes="180x180" eleventy:ignore><link href="/assets/img/touch-icon-ipad-retina.png" rel="apple-touch-icon" sizes="167x167" eleventy:ignore><meta name="twitter:card" content="summary"><meta name="twitter:site" content="@dart_lang"><meta name="twitter:title" content="Effective Dart: Usage"><meta name="twitter:description" content="Guidelines for using language features to write maintainable code."><meta property="og:title" content="Effective Dart: Usage"><meta property="og:description" content="Guidelines for using language features to write maintainable code."><meta property="og:url" content="/effective-dart/usage/"><meta property="og:image" content="/assets/img/logo/dart-logo-for-shares.png?2" eleventy:ignore><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;500;700&display=swap" rel="stylesheet"><link href="https://fonts.googleapis.com/css2?family=Google+Sans+Display:wght@400&display=swap" rel="stylesheet"><link href="https://fonts.googleapis.com/css2?family=Google+Sans+Mono:wght@400;500;700&display=swap" rel="stylesheet"><link href="https://fonts.googleapis.com/css2?family=Google+Sans+Text:wght@400;500;700&display=swap" rel="stylesheet"><link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0..1,0" rel="stylesheet"><link rel="stylesheet" href="/assets/css/main.css?v=3"><script src="/assets/js/os-tabs.js?v=3"></script><script src="/assets/js/main.js?v=3"></script><script>!function(e,a,t,n,c,o,s){e.GoogleAnalyticsObject=c,e[c]=e[c]||function(){(e[c].q=e[c].q||[]).push(arguments)},e[c].l=1*new Date,o=a.createElement(t),s=a.getElementsByTagName(t)[0],o.async=1,o.src="//www.google-analytics.com/analytics.js",s.parentNode.insertBefore(o,s)}(window,document,"script",0,"ga"),ga("create","UA-26406144-4","auto"),ga("send","pageview")</script></head><body class="default.html"><a id="skip-to-main" class="filled-button" href="#site-content-title" tabindex="1">Skip to main content</a><section id="cookie-notice"><div class="container"><p>dart.dev uses cookies from Google to deliver and enhance the quality of its services and to analyze traffic.</p><div class="button-group"><a class="text-button" href="https://policies.google.com/technologies/cookies" target="_blank" rel="noopener">Learn more</a> <button id="cookie-consent" class="filled-button">OK, got it</button></div></div></section><noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-5VSZM5J" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript><div id="site-banner" role="alert"><p>Announcing Dart 3.7! Find out about updates to the language, analyzer, pub.dev, and more, in the <a href="https://medium.com/dartlang/announcing-dart-3-7-bf864a1b195c" target="_blank">blog post</a>.</p></div><header id="site-header"><nav id="mainnav"><div id="menu-toggle"><span class="material-symbols" title="Toggle side navigation menu." aria-label="Toggle side navigation menu." type="button">menu</span></div><a href="/" class="brand" title="Dart"><img src="/assets/img/logo/logo-white-text.svg" alt="Dart"></a><ul class="navbar"><li><a href="/overview" class="nav-link">Overview</a></li><li class="mainnav__get-started"><a href="/docs" class="nav-link active"><span>Docs</span></a></li><li><a href="/community" class="nav-link">Community</a></li><li><a href="/#try-dart" class="nav-link">Try Dart</a></li><li><a href="/get-dart" class="nav-link">Get Dart</a></li><li class="searchfield"><form action="/search" class="site-header-search form-inline" id="cse-search-box"><input type="hidden" name="cx" value="011220921317074318178:_yy-tmb5t_i"> <input type="hidden" name="ie" value="UTF-8"> <input type="hidden" name="hl" value="en"> <input class="site-header-searchfield form-control search-field" type="search" name="q" id="search-main" autocomplete="off" placeholder="Search" aria-label="Search"></form></li></ul></nav></header><div id="site-below-header"><div id="site-main-row"><div id="sidenav"><form action="/search/" class="site-header-search form-inline"><input class="site-header-searchfield form-control search-field" type="search" name="q" id="search-side" autocomplete="off" placeholder="Search" aria-label="Search"></form><ul class="navbar-nav"><li aria-hidden="true"><div class="sidenav-divider"></div></li><li class="nav-item"><a href="/overview" class="nav-link">Overview</a></li><li class="nav-item"><a href="/community" class="nav-link">Community</a></li><li class="nav-item"><a href="https://dartpad.dev" class="nav-link">Try Dart</a></li><li class="nav-item"><a href="/get-dart" class="nav-link">Get Dart</a></li><li class="nav-item"><a href="/docs" class="nav-link">Docs</a></li><li aria-hidden="true"><div class="sidenav-divider"></div></li></ul><ul class="nav"><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#-sidenav-1" role="button" aria-expanded="false" aria-controls="-sidenav-1"><span>Language</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-1"><li class="nav-item"><a class="nav-link" href="/language"><div><span>Introduction</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-1-2" role="button" aria-expanded="false" aria-controls="-sidenav-1-2"><span>Syntax basics</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-1-2"><li class="nav-item"><a class="nav-link" href="/language/variables"><div><span>Variables</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/operators"><div><span>Operators</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/comments"><div><span>Comments</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/metadata"><div><span>Metadata</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/libraries"><div><span>Libraries & imports</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/keywords"><div><span>Keywords</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-1-3" role="button" aria-expanded="false" aria-controls="-sidenav-1-3"><span>Types</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-1-3"><li class="nav-item"><a class="nav-link" href="/language/built-in-types"><div><span>Built-in types</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/records"><div><span>Records</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/collections"><div><span>Collections</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/generics"><div><span>Generics</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/typedefs"><div><span>Typedefs</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/type-system"><div><span>Type system</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-1-4" role="button" aria-expanded="false" aria-controls="-sidenav-1-4"><span>Patterns</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-1-4"><li class="nav-item"><a class="nav-link" href="/language/patterns"><div><span>Overview & usage</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/pattern-types"><div><span>Pattern types</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records" target="_blank" rel="noopener"><div><span>Applied tutorial</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li></ul></li><li class="nav-item"><a class="nav-link" href="/language/functions"><div><span>Functions</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-1-6" role="button" aria-expanded="false" aria-controls="-sidenav-1-6"><span>Control flow</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-1-6"><li class="nav-item"><a class="nav-link" href="/language/loops"><div><span>Loops</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/branches"><div><span>Branches</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/error-handling"><div><span>Error handling</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-1-7" role="button" aria-expanded="false" aria-controls="-sidenav-1-7"><span>Classes & objects</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-1-7"><li class="nav-item"><a class="nav-link" href="/language/classes"><div><span>Classes</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/constructors"><div><span>Constructors</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/methods"><div><span>Methods</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/extend"><div><span>Extend a class</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/mixins"><div><span>Mixins</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/enums"><div><span>Enums</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/extension-methods"><div><span>Extension methods</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/extension-types"><div><span>Extension types</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/callable-objects"><div><span>Callable objects</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-1-8" role="button" aria-expanded="false" aria-controls="-sidenav-1-8"><span>Class modifiers</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-1-8"><li class="nav-item"><a class="nav-link" href="/language/class-modifiers"><div><span>Overview & usage</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/class-modifiers-for-apis"><div><span>Class modifiers for API maintainers</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/modifier-reference"><div><span>Reference</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-1-9" role="button" aria-expanded="false" aria-controls="-sidenav-1-9"><span>Concurrency</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-1-9"><li class="nav-item"><a class="nav-link" href="/language/concurrency"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/async"><div><span>Asynchronous support</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/isolates"><div><span>Isolates</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-1-10" role="button" aria-expanded="false" aria-controls="-sidenav-1-10"><span>Null safety</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-1-10"><li class="nav-item"><a class="nav-link" href="/null-safety"><div><span>Sound null safety</span></div></a></li><li class="nav-item"><a class="nav-link" href="/null-safety/migration-guide"><div><span>Migrating to null safety</span></div></a></li><li class="nav-item"><a class="nav-link" href="/null-safety/understanding-null-safety"><div><span>Understanding null safety</span></div></a></li><li class="nav-item"><a class="nav-link" href="/null-safety/unsound-null-safety"><div><span>Unsound null safety</span></div></a></li><li class="nav-item"><a class="nav-link" href="/null-safety/faq"><div><span>FAQ</span></div></a></li></ul></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#-sidenav-2" role="button" aria-expanded="false" aria-controls="-sidenav-2"><span>Core libraries</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-2"><li class="nav-item"><a class="nav-link" href="/libraries"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/dart-core"><div><span>dart:core</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/dart-async"><div><span>dart:async</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/dart-math"><div><span>dart:math</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/dart-convert"><div><span>dart:convert</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/dart-io"><div><span>dart:io</span></div></a></li><li class="nav-item"><a class="nav-link" href="/interop/js-interop"><div><span>dart:js_interop</span></div></a></li><div class="sidenav-divider"></div><li class="nav-item"><a class="nav-link" href="/libraries/collections/iterables"><div><span>Iterable collections</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-2-10" role="button" aria-expanded="false" aria-controls="-sidenav-2-10"><span>Asynchronous programming</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-2-10"><li class="nav-item"><a class="nav-link" href="/libraries/async/async-await"><div><span>Tutorial</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/async/futures-error-handling"><div><span>Futures and error handling</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/async/using-streams"><div><span>Using streams</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/async/creating-streams"><div><span>Creating streams</span></div></a></li></ul></li></ul></li><li class="nav-item"><button class="nav-link active collapsible" data-toggle="collapse" data-target="#-sidenav-3" role="button" aria-expanded="true" aria-controls="-sidenav-3"><span>Effective Dart</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse show" id="-sidenav-3"><li class="nav-item"><a class="nav-link" href="/effective-dart"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/effective-dart/style"><div><span>Style</span></div></a></li><li class="nav-item"><a class="nav-link" href="/effective-dart/documentation"><div><span>Documentation</span></div></a></li><li class="nav-item"><a class="nav-link active" href="/effective-dart/usage"><div><span>Usage</span></div></a></li><li class="nav-item"><a class="nav-link" href="/effective-dart/design"><div><span>Design</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#-sidenav-4" role="button" aria-expanded="false" aria-controls="-sidenav-4"><span>Packages</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-4"><li class="nav-item"><a class="nav-link" href="/tools/pub/packages"><div><span>How to use packages</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/useful-packages"><div><span>Commonly used packages</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/create-packages"><div><span>Creating packages</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/publishing"><div><span>Publishing packages</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/writing-package-pages"><div><span>Writing package pages</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/workspaces"><div><span>Workspaces (monorepo support)</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-4-7" role="button" aria-expanded="false" aria-controls="-sidenav-4-7"><span>Package reference</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-4-7"><li class="nav-item"><a class="nav-link" href="/tools/pub/dependencies"><div><span>Dependencies</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/glossary"><div><span>Glossary</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/package-layout"><div><span>Package layout conventions</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/environment-variables"><div><span>Pub environment variables</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/pubspec"><div><span>Pubspec file</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/troubleshoot"><div><span>Troubleshooting pub</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/verified-publishers"><div><span>Verified publishers</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/security-advisories"><div><span>Security advisories</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/versioning"><div><span>Versioning</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/custom-package-repositories"><div><span>Custom package repositories</span></div></a></li></ul></li><li class="nav-item"><a class="nav-link" href="/tools/pub/private-files"><div><span>What not to commit</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#-sidenav-5" role="button" aria-expanded="false" aria-controls="-sidenav-5"><span>Development</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-5"><li class="nav-item"><a class="nav-link" href="/libraries/serialization/json"><div><span>JSON serialization</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/language/number-representation"><div><span>Number representation</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/google-apis"><div><span>Google APIs</span></div></a></li><li class="nav-item"><a class="nav-link" href="/multiplatform-apps"><div><span>Multi-platform apps</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-5-5" role="button" aria-expanded="false" aria-controls="-sidenav-5-5"><span>Command-line & server apps</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-5-5"><li class="nav-item"><a class="nav-link" href="/server"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tutorials/server/get-started"><div><span>Get started</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tutorials/server/cmdline"><div><span>Write command-line apps</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tutorials/server/fetch-data"><div><span>Fetch data from the internet</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tutorials/server/httpserver"><div><span>Write HTTP servers</span></div></a></li><li class="nav-item"><a class="nav-link" href="/server/libraries"><div><span>Libraries & packages</span></div></a></li><li class="nav-item"><a class="nav-link" href="/server/google-cloud"><div><span>Google Cloud</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-5-6" role="button" aria-expanded="false" aria-controls="-sidenav-5-6"><span>Web apps</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-5-6"><li class="nav-item"><a class="nav-link" href="/web"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/web/get-started"><div><span>Get started</span></div></a></li><li class="nav-item"><a class="nav-link" href="/web/deployment"><div><span>Deployment</span></div></a></li><li class="nav-item"><a class="nav-link" href="/web/libraries"><div><span>Libraries & packages</span></div></a></li><li class="nav-item"><a class="nav-link" href="/web/wasm"><div><span>Wasm compilation</span></div></a></li></ul></li><li class="nav-item"><a class="nav-link" href="/libraries/core/environment-declarations"><div><span>Environment declarations</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#-sidenav-6" role="button" aria-expanded="false" aria-controls="-sidenav-6"><span>Interoperability</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-6"><li class="nav-item"><a class="nav-link" href="/interop/c-interop"><div><span>C interop</span></div></a></li><li class="nav-item"><a class="nav-link" href="/interop/objective-c-interop"><div><span>Objective-C & Swift interop</span></div></a></li><li class="nav-item"><a class="nav-link" href="/interop/java-interop"><div><span>Java & Kotlin interop</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-6-4" role="button" aria-expanded="false" aria-controls="-sidenav-6-4"><span>JavaScript interop</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-6-4"><li class="nav-item"><a class="nav-link" href="/interop/js-interop"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/interop/js-interop/usage"><div><span>Usage</span></div></a></li><li class="nav-item"><a class="nav-link" href="/interop/js-interop/js-types"><div><span>JS types</span></div></a></li><li class="nav-item"><a class="nav-link" href="/interop/js-interop/tutorials"><div><span>Tutorials</span></div></a></li><li class="nav-item"><a class="nav-link" href="/interop/js-interop/past-js-interop"><div><span>Past JS interop</span></div></a></li><div class="sidenav-divider"></div><li class="nav-item"><a class="nav-link" href="/interop/js-interop/package-web"><div><span>Web interop</span></div></a></li></ul></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#-sidenav-7" role="button" aria-expanded="false" aria-controls="-sidenav-7"><span>Tools & techniques</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-7"><li class="nav-item"><a class="nav-link" href="/tools"><div><span>Overview</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-7-2" role="button" aria-expanded="false" aria-controls="-sidenav-7-2"><span>Editors & debuggers</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-7-2"><li class="nav-item"><a class="nav-link" href="/tools/jetbrains-plugin"><div><span>IntelliJ & Android Studio</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/vs-code"><div><span>VS Code</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-devtools"><div><span>Dart DevTools</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-7-2-4" role="button" aria-expanded="false" aria-controls="-sidenav-7-2-4"><span>DartPad</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-7-2-4"><li class="nav-item"><a class="nav-link" href="/tools/dartpad"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dartpad/troubleshoot"><div><span>Troubleshooting DartPad</span></div></a></li></ul></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-7-3" role="button" aria-expanded="false" aria-controls="-sidenav-7-3"><span>Command-line tools</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-7-3"><li class="nav-item"><button class="nav-link collapsible" data-toggle="collapse" data-target="#-sidenav-7-3-1" role="button" aria-expanded="true" aria-controls="-sidenav-7-3-1"><span>Dart SDK</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse show" id="-sidenav-7-3-1"><li class="nav-item"><a class="nav-link" href="/tools/sdk"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-tool"><div><span>dart</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-analyze"><div><span>dart analyze</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-compile"><div><span>dart compile</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-create"><div><span>dart create</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-doc"><div><span>dart doc</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-fix"><div><span>dart fix</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-format"><div><span>dart format</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-info"><div><span>dart info</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/cmd"><div><span>dart pub</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-run"><div><span>dart run</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-test"><div><span>dart test</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dartaotruntime"><div><span>dartaotruntime</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/experiment-flags"><div><span>Experiment flags</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible" data-toggle="collapse" data-target="#-sidenav-7-3-2" role="button" aria-expanded="true" aria-controls="-sidenav-7-3-2"><span>Other command-line tools</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse show" id="-sidenav-7-3-2"><li class="nav-item"><a class="nav-link" href="/tools/build_runner"><div><span>build_runner</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/webdev"><div><span>webdev</span></div></a></li></ul></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-7-4" role="button" aria-expanded="false" aria-controls="-sidenav-7-4"><span>Static analysis</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-7-4"><li class="nav-item"><a class="nav-link" href="/tools/analysis"><div><span>Customizing static analysis</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/non-promotion-reasons"><div><span>Fixing type promotion failures</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/linter-rules"><div><span>Linter rules</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/diagnostic-messages"><div><span>Diagnostic messages</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-7-5" role="button" aria-expanded="false" aria-controls="-sidenav-7-5"><span>Testing & optimization</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-7-5"><li class="nav-item"><a class="nav-link" href="/tools/testing"><div><span>Testing</span></div></a></li><li class="nav-item"><a class="nav-link" href="/web/debugging"><div><span>Debugging web apps</span></div></a></li></ul></li></ul></li><li aria-hidden="true"><div class="sidenav-divider"></div></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#-sidenav-9" role="button" aria-expanded="false" aria-controls="-sidenav-9"><span>Resources</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-9"><li class="nav-item"><a class="nav-link" href="/resources/dart-cheatsheet"><div><span>Language cheatsheet</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/breaking-changes"><div><span>Breaking changes</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/language/evolution"><div><span>Language evolution</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/language/spec"><div><span>Language specification</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/dart-3-migration"><div><span>Dart 3 migration guide</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-9-6" role="button" aria-expanded="false" aria-controls="-sidenav-9-6"><span>Coming from ...</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-9-6"><li class="nav-item"><a class="nav-link" href="/resources/coming-from/js-to-dart"><div><span>JavaScript to Dart</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/coming-from/swift-to-dart"><div><span>Swift to Dart</span></div></a></li></ul></li><div class="sidenav-divider"></div><li class="nav-item"><a class="nav-link" href="/resources/faq"><div><span>FAQ</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/glossary"><div><span>Glossary</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/books"><div><span>Books</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/videos"><div><span>Videos</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tutorials"><div><span>Tutorials</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible" data-toggle="collapse" data-target="#-sidenav-10" role="button" aria-expanded="true" aria-controls="-sidenav-10"><span>Related sites</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse show" id="-sidenav-10"><li class="nav-item"><a class="nav-link" href="https://api.dart.dev" target="_blank" rel="noopener"><div><span>API reference</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://medium.com/dartlang" target="_blank" rel="noopener"><div><span>Blog</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://dartpad.dev" target="_blank" rel="noopener"><div><span>DartPad (online editor)</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://flutter.dev" target="_blank" rel="noopener"><div><span>Flutter</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://pub.dev" target="_blank" rel="noopener"><div><span>Package site</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li></ul></li></ul></div><main id="page-content"><div id="site-toc--side" class="site-toc"><header class="site-toc__title">Contents</header><ul class="section-nav"><li class="toc-entry nav-item"><a class="nav-link" href="#libraries">Libraries</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#do-use-strings-in-part-of-directives">DO use strings in part of directives</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#dont-import-libraries-that-are-inside-the-src-directory-of-another-package">DON'T import libraries that are inside the src directory of another package</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#dont-allow-an-import-path-to-reach-into-or-out-of-lib">DON'T allow an import path to reach into or out of lib</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#prefer-relative-import-paths">PREFER relative import paths</a></li></ul></li><li class="toc-entry nav-item"><a class="nav-link" href="#null">Null</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#dont-explicitly-initialize-variables-to-null">DON'T explicitly initialize variables to null</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#dont-use-an-explicit-default-value-of-null">DON'T use an explicit default value of null</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#dont-use-true-or-false-in-equality-operations">DON'T use true or false in equality operations</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#avoid-late-variables-if-you-need-to-check-whether-they-are-initialized">AVOID late variables if you need to check whether they are initialized</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#consider-type-promotion-or-null-check-patterns-for-using-nullable-types">CONSIDER type promotion or null-check patterns for using nullable types</a></li></ul></li><li class="toc-entry nav-item"><a class="nav-link" href="#strings">Strings</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#do-use-adjacent-strings-to-concatenate-string-literals">DO use adjacent strings to concatenate string literals</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#prefer-using-interpolation-to-compose-strings-and-values">PREFER using interpolation to compose strings and values</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#avoid-using-curly-braces-in-interpolation-when-not-needed">AVOID using curly braces in interpolation when not needed</a></li></ul></li><li class="toc-entry nav-item"><a class="nav-link" href="#collections">Collections</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#do-use-collection-literals-when-possible">DO use collection literals when possible</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#dont-use-length-to-see-if-a-collection-is-empty">DON'T use .length to see if a collection is empty</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#avoid-using-iterable-foreach-with-a-function-literal">AVOID using Iterable.forEach() with a function literal</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#dont-use-list-from-unless-you-intend-to-change-the-type-of-the-result">DON'T use List.from() unless you intend to change the type of the result</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#do-use-wheretype-to-filter-a-collection-by-type">DO use whereType() to filter a collection by type</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#dont-use-cast-when-a-nearby-operation-will-do">DON'T use cast() when a nearby operation will do</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#avoid-using-cast">AVOID using cast()</a></li></ul></li><li class="toc-entry nav-item"><a class="nav-link" href="#functions">Functions</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#do-use-a-function-declaration-to-bind-a-function-to-a-name">DO use a function declaration to bind a function to a name</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#dont-create-a-lambda-when-a-tear-off-will-do">DON'T create a lambda when a tear-off will do</a></li></ul></li><li class="toc-entry nav-item"><a class="nav-link" href="#variables">Variables</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#do-follow-a-consistent-rule-for-var-and-final-on-local-variables">DO follow a consistent rule for var and final on local variables</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#avoid-storing-what-you-can-calculate">AVOID storing what you can calculate</a></li></ul></li><li class="toc-entry nav-item"><a class="nav-link" href="#members">Members</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#dont-wrap-a-field-in-a-getter-and-setter-unnecessarily">DON'T wrap a field in a getter and setter unnecessarily</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#prefer-using-a-final-field-to-make-a-read-only-property">PREFER using a final field to make a read-only property</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#consider-using-for-simple-members">CONSIDER using => for simple members</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#dont-use-this-when-not-needed-to-avoid-shadowing">DON'T use this. except to redirect to a named constructor or to avoid shadowing</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#do-initialize-fields-at-their-declaration-when-possible">DO initialize fields at their declaration when possible</a></li></ul></li><li class="toc-entry nav-item"><a class="nav-link" href="#constructors">Constructors</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#do-use-initializing-formals-when-possible">DO use initializing formals when possible</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#dont-use-late-when-a-constructor-initializer-list-will-do">DON'T use late when a constructor initializer list will do</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#do-use-instead-of-for-empty-constructor-bodies">DO use ; instead of {} for empty constructor bodies</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#dont-use-new">DON'T use new</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#dont-use-const-redundantly">DON'T use const redundantly</a></li></ul></li><li class="toc-entry nav-item"><a class="nav-link" href="#error-handling">Error handling</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#avoid-catches-without-on-clauses">AVOID catches without on clauses</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#dont-discard-errors-from-catches-without-on-clauses">DON'T discard errors from catches without on clauses</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#do-throw-objects-that-implement-error-only-for-programmatic-errors">DO throw objects that implement Error only for programmatic errors</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#dont-explicitly-catch-error-or-types-that-implement-it">DON'T explicitly catch Error or types that implement it</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#do-use-rethrow-to-rethrow-a-caught-exception">DO use rethrow to rethrow a caught exception</a></li></ul></li><li class="toc-entry nav-item"><a class="nav-link" href="#asynchrony">Asynchrony</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#prefer-asyncawait-over-using-raw-futures">PREFER async/await over using raw futures</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#dont-use-async-when-it-has-no-useful-effect">DON'T use async when it has no useful effect</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#consider-using-higher-order-methods-to-transform-a-stream">CONSIDER using higher-order methods to transform a stream</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#avoid-using-completer-directly">AVOID using Completer directly</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#do-test-for-futuret-when-disambiguating-a-futureort-whose-type-argument-could-be-object">DO test for Future<T> when disambiguating a FutureOr<T> whose type argument could be Object</a></li></ul></li></ul></div><article><div class="content"><div id="site-content-title"><h1>Effective Dart: Usage</h1></div><div id="site-toc--inline" class="site-toc toc-collapsible toc-collapsed"><header class="site-toc__title">Contents <span class="site-toc--inline__toggle toc-toggle-down"><i class="material-symbols">keyboard_arrow_down</i></span> <span class="site-toc--inline__toggle toc-toggle-up"><i class="material-symbols">keyboard_arrow_up</i></span></header><ul class="section-nav"><li class="toc-entry"><a href="#libraries">Libraries</a><ul><li class="toc-entry"><a href="#do-use-strings-in-part-of-directives">DO use strings in part of directives</a></li><li class="toc-entry"><a href="#dont-import-libraries-that-are-inside-the-src-directory-of-another-package">DON'T import libraries that are inside the src directory of another package</a></li><li class="toc-entry"><a href="#dont-allow-an-import-path-to-reach-into-or-out-of-lib">DON'T allow an import path to reach into or out of lib</a></li><li class="toc-entry"><a href="#prefer-relative-import-paths">PREFER relative import paths</a></li></ul></li><li class="toc-entry"><a href="#null">Null</a><ul><li class="toc-entry"><a href="#dont-explicitly-initialize-variables-to-null">DON'T explicitly initialize variables to null</a></li><li class="toc-entry"><a href="#dont-use-an-explicit-default-value-of-null">DON'T use an explicit default value of null</a></li><li class="toc-entry"><a href="#dont-use-true-or-false-in-equality-operations">DON'T use true or false in equality operations</a></li><li class="toc-entry"><a href="#avoid-late-variables-if-you-need-to-check-whether-they-are-initialized">AVOID late variables if you need to check whether they are initialized</a></li><li class="toc-entry"><a href="#consider-type-promotion-or-null-check-patterns-for-using-nullable-types">CONSIDER type promotion or null-check patterns for using nullable types</a></li></ul></li><li class="toc-entry"><a href="#strings">Strings</a><ul><li class="toc-entry"><a href="#do-use-adjacent-strings-to-concatenate-string-literals">DO use adjacent strings to concatenate string literals</a></li><li class="toc-entry"><a href="#prefer-using-interpolation-to-compose-strings-and-values">PREFER using interpolation to compose strings and values</a></li><li class="toc-entry"><a href="#avoid-using-curly-braces-in-interpolation-when-not-needed">AVOID using curly braces in interpolation when not needed</a></li></ul></li><li class="toc-entry"><a href="#collections">Collections</a><ul><li class="toc-entry"><a href="#do-use-collection-literals-when-possible">DO use collection literals when possible</a></li><li class="toc-entry"><a href="#dont-use-length-to-see-if-a-collection-is-empty">DON'T use .length to see if a collection is empty</a></li><li class="toc-entry"><a href="#avoid-using-iterable-foreach-with-a-function-literal">AVOID using Iterable.forEach() with a function literal</a></li><li class="toc-entry"><a href="#dont-use-list-from-unless-you-intend-to-change-the-type-of-the-result">DON'T use List.from() unless you intend to change the type of the result</a></li><li class="toc-entry"><a href="#do-use-wheretype-to-filter-a-collection-by-type">DO use whereType() to filter a collection by type</a></li><li class="toc-entry"><a href="#dont-use-cast-when-a-nearby-operation-will-do">DON'T use cast() when a nearby operation will do</a></li><li class="toc-entry"><a href="#avoid-using-cast">AVOID using cast()</a></li></ul></li><li class="toc-entry"><a href="#functions">Functions</a><ul><li class="toc-entry"><a href="#do-use-a-function-declaration-to-bind-a-function-to-a-name">DO use a function declaration to bind a function to a name</a></li><li class="toc-entry"><a href="#dont-create-a-lambda-when-a-tear-off-will-do">DON'T create a lambda when a tear-off will do</a></li></ul></li><li class="toc-entry"><a href="#variables">Variables</a><ul><li class="toc-entry"><a href="#do-follow-a-consistent-rule-for-var-and-final-on-local-variables">DO follow a consistent rule for var and final on local variables</a></li><li class="toc-entry"><a href="#avoid-storing-what-you-can-calculate">AVOID storing what you can calculate</a></li></ul></li><li class="toc-entry"><a href="#members">Members</a><ul><li class="toc-entry"><a href="#dont-wrap-a-field-in-a-getter-and-setter-unnecessarily">DON'T wrap a field in a getter and setter unnecessarily</a></li><li class="toc-entry"><a href="#prefer-using-a-final-field-to-make-a-read-only-property">PREFER using a final field to make a read-only property</a></li><li class="toc-entry"><a href="#consider-using-for-simple-members">CONSIDER using => for simple members</a></li><li class="toc-entry"><a href="#dont-use-this-when-not-needed-to-avoid-shadowing">DON'T use this. except to redirect to a named constructor or to avoid shadowing</a></li><li class="toc-entry"><a href="#do-initialize-fields-at-their-declaration-when-possible">DO initialize fields at their declaration when possible</a></li></ul></li><li class="toc-entry"><a href="#constructors">Constructors</a><ul><li class="toc-entry"><a href="#do-use-initializing-formals-when-possible">DO use initializing formals when possible</a></li><li class="toc-entry"><a href="#dont-use-late-when-a-constructor-initializer-list-will-do">DON'T use late when a constructor initializer list will do</a></li><li class="toc-entry"><a href="#do-use-instead-of-for-empty-constructor-bodies">DO use ; instead of {} for empty constructor bodies</a></li><li class="toc-entry"><a href="#dont-use-new">DON'T use new</a></li><li class="toc-entry"><a href="#dont-use-const-redundantly">DON'T use const redundantly</a></li></ul></li><li class="toc-entry"><a href="#error-handling">Error handling</a><ul><li class="toc-entry"><a href="#avoid-catches-without-on-clauses">AVOID catches without on clauses</a></li><li class="toc-entry"><a href="#dont-discard-errors-from-catches-without-on-clauses">DON'T discard errors from catches without on clauses</a></li><li class="toc-entry"><a href="#do-throw-objects-that-implement-error-only-for-programmatic-errors">DO throw objects that implement Error only for programmatic errors</a></li><li class="toc-entry"><a href="#dont-explicitly-catch-error-or-types-that-implement-it">DON'T explicitly catch Error or types that implement it</a></li><li class="toc-entry"><a href="#do-use-rethrow-to-rethrow-a-caught-exception">DO use rethrow to rethrow a caught exception</a></li></ul></li><li class="toc-entry"><a href="#asynchrony">Asynchrony</a><ul><li class="toc-entry"><a href="#prefer-asyncawait-over-using-raw-futures">PREFER async/await over using raw futures</a></li><li class="toc-entry"><a href="#dont-use-async-when-it-has-no-useful-effect">DON'T use async when it has no useful effect</a></li><li class="toc-entry"><a href="#consider-using-higher-order-methods-to-transform-a-stream">CONSIDER using higher-order methods to transform a stream</a></li><li class="toc-entry"><a href="#avoid-using-completer-directly">AVOID using Completer directly</a></li><li class="toc-entry"><a href="#do-test-for-futuret-when-disambiguating-a-futureort-whose-type-argument-could-be-object">DO test for Future<T> when disambiguating a FutureOr<T> whose type argument could be Object</a></li></ul></li></ul><span class="site-toc--inline__toggle toc-toggle-more-items"><i class="material-symbols">more_horiz</i></span></div> <?code-excerpt plaster="none"?> <?code-excerpt replace="/([A-Z]\w*)\d\b/$1/g"?> <?code-excerpt path-base="misc/lib/effective_dart"?> <p>You can use these guidelines every day in the bodies of your Dart code. <em>Users</em> of your library may not be able to tell that you've internalized the ideas here, but <em>maintainers</em> of it sure will.</p><div class="header-wrapper"><h2 id="libraries">Libraries</h2><a class="heading-link" href="#libraries" aria-label="Link to 'Libraries' section">#</a></div><p>These guidelines help you compose your program out of multiple files in a consistent, maintainable way. To keep these guidelines brief, they use "import" to cover <code>import</code> and <code>export</code> directives. The guidelines apply equally to both.</p><div class="header-wrapper"><h3 id="do-use-strings-in-part-of-directives">DO use strings in <code>part of</code> directives</h3><a class="heading-link" href="#do-use-strings-in-part-of-directives" aria-label="Link to 'DO use strings in part of directives' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/use_string_in_part_of_directives">use_string_in_part_of_directives</a></p><p>Many Dart developers avoid using <code>part</code> entirely. They find it easier to reason about their code when each library is a single file. If you do choose to use <code>part</code> to split part of a library out into another file, Dart requires the other file to in turn indicate which library it's a part of.</p><p>Dart allows the <code>part of</code> directive to use the <em>name</em> of a library. Naming libraries is a legacy feature that is now <a href="/effective-dart/style#dont-explicitly-name-libraries">discouraged</a>. Library names can introduce ambiguity when determining which library a part belongs to.</p><p>The preferred syntax is to use a URI string that points directly to the library file. If you have some library, <code>my_library.dart</code>, that contains:</p> <?code-excerpt "my_library.dart" remove="ignore_for_file"?> <div class="code-block-wrapper language-dart"><div class="code-block-header">my_library.dart</div><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">library</span><span style="color:#222222"> my_library;</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324">part</span><span style="color:#11796D"> 'some/other/file.dart'</span><span style="color:#222222">;</span></span></code></pre></div></div><p>Then the part file should use the library file's URI string:</p> <?code-excerpt "some/other/file.dart"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">part of</span><span style="color:#11796D"> '../../my_library.dart'</span><span style="color:#222222">;</span></span></code></pre></div></div><p>Not the library name:</p> <?code-excerpt "some/other/file_2.dart (part-of)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">part of</span><span style="color:#222222"> my_library;</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="dont-import-libraries-that-are-inside-the-src-directory-of-another-package">DON'T import libraries that are inside the <code>src</code> directory of another package</h3><a class="heading-link" href="#dont-import-libraries-that-are-inside-the-src-directory-of-another-package" aria-label="Link to 'DON'T import libraries that are inside the src directory of another package' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/implementation_imports">implementation_imports</a></p><p>The <code>src</code> directory under <code>lib</code> <a href="/tools/pub/package-layout">is specified</a> to contain libraries private to the package's own implementation. The way package maintainers version their package takes this convention into account. They are free to make sweeping changes to code under <code>src</code> without it being a breaking change to the package.</p><p>That means that if you import some other package's private library, a minor, theoretically non-breaking point release of that package could break your code.</p><div class="header-wrapper"><h3 id="dont-allow-an-import-path-to-reach-into-or-out-of-lib">DON'T allow an import path to reach into or out of <code>lib</code></h3><a class="heading-link" href="#dont-allow-an-import-path-to-reach-into-or-out-of-lib" aria-label="Link to 'DON'T allow an import path to reach into or out of lib' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/avoid_relative_lib_imports">avoid_relative_lib_imports</a></p><p>A <code>package:</code> import lets you access a library inside a package's <code>lib</code> directory without having to worry about where the package is stored on your computer. For this to work, you cannot have imports that require the <code>lib</code> to be in some location on disk relative to other files. In other words, a relative import path in a file inside <code>lib</code> can't reach out and access a file outside of the <code>lib</code> directory, and a library outside of <code>lib</code> can't use a relative path to reach into the <code>lib</code> directory. Doing either leads to confusing errors and broken programs.</p><p>For example, say your directory structure looks like this:</p><div class="code-block-wrapper language-plaintext"><div class="code-block-body"><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span>my_package</span></span> <span class="line"><span>└─ lib</span></span> <span class="line"><span> └─ api.dart</span></span> <span class="line"><span> test</span></span> <span class="line"><span> └─ api_test.dart</span></span></code></pre></div></div><p>And say <code>api_test.dart</code> imports <code>api.dart</code> in two ways:</p><div class="code-block-wrapper language-dart"><div class="code-block-header">api_test.dart</div><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">import</span><span style="color:#11796D"> 'package:my_package/api.dart'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#D43324">import</span><span style="color:#11796D"> '../lib/api.dart'</span><span style="color:#222222">;</span></span></code></pre></div></div><p>Dart thinks those are imports of two completely unrelated libraries. To avoid confusing Dart and yourself, follow these two rules:</p><ul><li>Don't use <code>/lib/</code> in import paths.</li><li>Don't use <code>../</code> to escape the <code>lib</code> directory.</li></ul><p>Instead, when you need to reach into a package's <code>lib</code> directory (even from the same package's <code>test</code> directory or any other top-level directory), use a <code>package:</code> import.</p><div class="code-block-wrapper language-dart"><div class="code-block-header">api_test.dart</div><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">import</span><span style="color:#11796D"> 'package:my_package/api.dart'</span><span style="color:#222222">;</span></span></code></pre></div></div><p>A package should never reach <em>out</em> of its <code>lib</code> directory and import libraries from other places in the package.</p><div class="header-wrapper"><h3 id="prefer-relative-import-paths">PREFER relative import paths</h3><a class="heading-link" href="#prefer-relative-import-paths" aria-label="Link to 'PREFER relative import paths' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/prefer_relative_imports">prefer_relative_imports</a></p><p>Whenever the previous rule doesn't come into play, follow this one. When an import does <em>not</em> reach across <code>lib</code>, prefer using relative imports. They're shorter. For example, say your directory structure looks like this:</p><div class="code-block-wrapper language-plaintext"><div class="code-block-body"><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span>my_package</span></span> <span class="line"><span>└─ lib</span></span> <span class="line"><span> ├─ src</span></span> <span class="line"><span> │ └─ stuff.dart</span></span> <span class="line"><span> │ └─ utils.dart</span></span> <span class="line"><span> └─ api.dart</span></span> <span class="line"><span> test</span></span> <span class="line"><span> │─ api_test.dart</span></span> <span class="line"><span> └─ test_utils.dart</span></span></code></pre></div></div><p>Here is how the various libraries should import each other:</p><div class="code-block-wrapper language-dart"><div class="code-block-header">lib/api.dart</div><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">import</span><span style="color:#11796D"> 'src/stuff.dart'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#D43324">import</span><span style="color:#11796D"> 'src/utils.dart'</span><span style="color:#222222">;</span></span></code></pre></div></div><div class="code-block-wrapper language-dart"><div class="code-block-header">lib/src/utils.dart</div><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">import</span><span style="color:#11796D"> '../api.dart'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#D43324">import</span><span style="color:#11796D"> 'stuff.dart'</span><span style="color:#222222">;</span></span></code></pre></div></div><div class="code-block-wrapper language-dart"><div class="code-block-header">test/api_test.dart</div><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">import</span><span style="color:#11796D"> 'package:my_package/api.dart'</span><span style="color:#222222">; </span><span style="color:#6E6E70">// Don't reach into 'lib'.</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324">import</span><span style="color:#11796D"> 'test_utils.dart'</span><span style="color:#222222">; </span><span style="color:#6E6E70">// Relative within 'test' is fine.</span></span></code></pre></div></div><div class="header-wrapper"><h2 id="null">Null</h2><a class="heading-link" href="#null" aria-label="Link to 'Null' section">#</a></div><div class="header-wrapper"><h3 id="dont-explicitly-initialize-variables-to-null">DON'T explicitly initialize variables to <code>null</code></h3><a class="heading-link" href="#dont-explicitly-initialize-variables-to-null" aria-label="Link to 'DON'T explicitly initialize variables to null' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/avoid_init_to_null">avoid_init_to_null</a></p><p>If a variable has a non-nullable type, Dart reports a compile error if you try to use it before it has been definitely initialized. If the variable is nullable, then it is implicitly initialized to <code>null</code> for you. There's no concept of "uninitialized memory" in Dart and no need to explicitly initialize a variable to <code>null</code> to be "safe".</p> <?code-excerpt "usage_good.dart (no-null-init)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Item</span><span style="color:#222222">? </span><span style="color:#6200EE">bestDeal</span><span style="color:#222222">(</span><span style="color:#0468D7">List</span><span style="color:#222222"><</span><span style="color:#0468D7">Item</span><span style="color:#222222">> cart) {</span></span> <span class="line"><span style="color:#0468D7"> Item</span><span style="color:#222222">? bestItem;</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> for</span><span style="color:#222222"> (</span><span style="color:#D43324">final</span><span style="color:#222222"> item </span><span style="color:#D43324">in</span><span style="color:#222222"> cart) {</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (bestItem == </span><span style="color:#11796D">null</span><span style="color:#222222"> || item.price < bestItem.price) {</span></span> <span class="line"><span style="color:#222222"> bestItem = item;</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> bestItem;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (no-null-init)" replace="/ = null/[!$&!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Item</span><span style="color:#222222">? </span><span style="color:#6200EE">bestDeal</span><span style="color:#222222">(</span><span style="color:#0468D7">List</span><span style="color:#222222"><</span><span style="color:#0468D7">Item</span><span style="color:#222222">> cart) {</span></span> <span class="line"><span style="color:#0468D7"> Item</span><span style="color:#222222">? bestItem</span><mark class="highlight"><span style="color:#222222"> = </span><span style="color:#11796D">null</span></mark><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> for</span><span style="color:#222222"> (</span><span style="color:#D43324">final</span><span style="color:#222222"> item </span><span style="color:#D43324">in</span><span style="color:#222222"> cart) {</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (bestItem == </span><span style="color:#11796D">null</span><span style="color:#222222"> || item.price < bestItem.price) {</span></span> <span class="line"><span style="color:#222222"> bestItem = item;</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> bestItem;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="dont-use-an-explicit-default-value-of-null">DON'T use an explicit default value of <code>null</code></h3><a class="heading-link" href="#dont-use-an-explicit-default-value-of-null" aria-label="Link to 'DON'T use an explicit default value of null' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/avoid_init_to_null">avoid_init_to_null</a></p><p>If you make a nullable parameter optional but don't give it a default value, the language implicitly uses <code>null</code> as the default, so there's no need to write it.</p> <?code-excerpt "usage_good.dart (default-value-null)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> error</span><span style="color:#222222">([</span><span style="color:#0468D7">String</span><span style="color:#222222">? message]) {</span></span> <span class="line"><span style="color:#222222"> stderr.</span><span style="color:#6200EE">write</span><span style="color:#222222">(message ?? </span><span style="color:#11796D">'</span><span style="color:#222222">\n</span><span style="color:#11796D">'</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (default-value-null)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> error</span><span style="color:#222222">([</span><span style="color:#0468D7">String</span><span style="color:#222222">? message = </span><span style="color:#11796D">null</span><span style="color:#222222">]) {</span></span> <span class="line"><span style="color:#222222"> stderr.</span><span style="color:#6200EE">write</span><span style="color:#222222">(message ?? </span><span style="color:#11796D">'</span><span style="color:#222222">\n</span><span style="color:#11796D">'</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p><a id="prefer-using--to-convert-null-to-a-boolean-value"></a></p><div class="header-wrapper"><h3 id="dont-use-true-or-false-in-equality-operations">DON'T use <code>true</code> or <code>false</code> in equality operations</h3><a class="heading-link" href="#dont-use-true-or-false-in-equality-operations" aria-label="Link to 'DON'T use true or false in equality operations' section">#</a></div><p>Using the equality operator to evaluate a <em>non-nullable</em> boolean expression against a boolean literal is redundant. It's always simpler to eliminate the equality operator, and use the unary negation operator <code>!</code> if necessary:</p> <?code-excerpt "usage_good.dart (non-null-boolean-expression)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">if</span><span style="color:#222222"> (nonNullableBool) {</span></span> <span class="line"><span style="color:#222222"> ...</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324">if</span><span style="color:#222222"> (!nonNullableBool) {</span></span> <span class="line"><span style="color:#222222"> ...</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (non-null-boolean-expression)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">if</span><span style="color:#222222"> (nonNullableBool == </span><span style="color:#11796D">true</span><span style="color:#222222">) {</span></span> <span class="line"><span style="color:#222222"> ...</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324">if</span><span style="color:#222222"> (nonNullableBool == </span><span style="color:#11796D">false</span><span style="color:#222222">) {</span></span> <span class="line"><span style="color:#222222"> ...</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>To evaluate a boolean expression that <em>is nullable</em>, you should use <code>??</code> or an explicit <code>!= null</code> check.</p> <?code-excerpt "usage_good.dart (nullable-boolean-expression)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#6E6E70">// If you want null to result in false:</span></span> <span class="line"><span style="color:#D43324">if</span><span style="color:#222222"> (nullableBool ?? </span><span style="color:#11796D">false</span><span style="color:#222222">) {</span></span> <span class="line"><span style="color:#222222"> ...</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">// If you want null to result in false</span></span> <span class="line"><span style="color:#6E6E70">// and you want the variable to type promote:</span></span> <span class="line"><span style="color:#D43324">if</span><span style="color:#222222"> (nullableBool != </span><span style="color:#11796D">null</span><span style="color:#222222"> && nullableBool) {</span></span> <span class="line"><span style="color:#222222"> ...</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (nullable-boolean-expression)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#6E6E70">// Static error if null:</span></span> <span class="line"><span style="color:#D43324">if</span><span style="color:#222222"> (nullableBool) {</span></span> <span class="line"><span style="color:#222222"> ...</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">// If you want null to be false:</span></span> <span class="line"><span style="color:#D43324">if</span><span style="color:#222222"> (nullableBool == </span><span style="color:#11796D">true</span><span style="color:#222222">) {</span></span> <span class="line"><span style="color:#222222"> ...</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p><code>nullableBool == true</code> is a viable expression, but shouldn't be used for several reasons:</p><ul><li><p>It doesn't indicate the code has anything to do with <code>null</code>.</p></li><li><p>Because it's not evidently <code>null</code> related, it can easily be mistaken for the non-nullable case, where the equality operator is redundant and can be removed. That's only true when the boolean expression on the left has no chance of producing null, but not when it can.</p></li><li><p>The boolean logic is confusing. If <code>nullableBool</code> is null, then <code>nullableBool == true</code> means the condition evaluates to <code>false</code>.</p></li></ul><p>The <code>??</code> operator makes it clear that something to do with null is happening, so it won't be mistaken for a redundant operation. The logic is much clearer too; the result of the expression being <code>null</code> is the same as the boolean literal.</p><p>Using a null-aware operator such as <code>??</code> on a variable inside a condition doesn't promote the variable to a non-nullable type. If you want the variable to be promoted inside the body of the <code>if</code> statement, it's better to use an explicit <code>!= null</code> check instead of <code>??</code>.</p><div class="header-wrapper"><h3 id="avoid-late-variables-if-you-need-to-check-whether-they-are-initialized">AVOID <code>late</code> variables if you need to check whether they are initialized</h3><a class="heading-link" href="#avoid-late-variables-if-you-need-to-check-whether-they-are-initialized" aria-label="Link to 'AVOID late variables if you need to check whether they are initialized' section">#</a></div><p>Dart offers no way to tell if a <code>late</code> variable has been initialized or assigned to. If you access it, it either immediately runs the initializer (if it has one) or throws an exception. Sometimes you have some state that's lazily initialized where <code>late</code> might be a good fit, but you also need to be able to <em>tell</em> if the initialization has happened yet.</p><p>Although you could detect initialization by storing the state in a <code>late</code> variable and having a separate boolean field that tracks whether the variable has been set, that's redundant because Dart <em>internally</em> maintains the initialized status of the <code>late</code> variable. Instead, it's usually clearer to make the variable non-<code>late</code> and nullable. Then you can see if the variable has been initialized by checking for <code>null</code>.</p><p>Of course, if <code>null</code> is a valid initialized value for the variable, then it probably does make sense to have a separate boolean field.</p><div class="header-wrapper"><h3 id="consider-type-promotion-or-null-check-patterns-for-using-nullable-types">CONSIDER type promotion or null-check patterns for using nullable types</h3><a class="heading-link" href="#consider-type-promotion-or-null-check-patterns-for-using-nullable-types" aria-label="Link to 'CONSIDER type promotion or null-check patterns for using nullable types' section">#</a></div><p>Checking that a nullable variable is not equal to <code>null</code> promotes the variable to a non-nullable type. That lets you access members on the variable and pass it to functions expecting a non-nullable type.</p><p>Type promotion is only supported, however, for local variables, parameters, and private final fields. Values that are open to manipulation <a href="/tools/non-promotion-reasons">can't be type promoted</a>.</p><p>Declaring members <a href="/effective-dart/design#prefer-making-declarations-private">private</a> and <a href="/effective-dart/design#prefer-making-fields-and-top-level-variables-final">final</a>, as we generally recommend, is often enough to bypass these limitations. But, that's not always an option.</p><p>One pattern to work around type promotion limitations is to use a <a href="/language/pattern-types#null-check">null-check pattern</a>. This simultaneously confirms the member's value is not null, and binds that value to a new non-nullable variable of the same base type.</p> <?code-excerpt "usage_good.dart (null-check-promo)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> UploadException</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> final</span><span style="color:#0468D7"> Response</span><span style="color:#222222">? response;</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> UploadException</span><span style="color:#222222">([</span><span style="color:#D43324">this</span><span style="color:#222222">.response]);</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> @override</span></span> <span class="line"><span style="color:#0468D7"> String</span><span style="color:#6200EE"> toString</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (</span><span style="color:#D43324">this</span><span style="color:#222222">.response </span><span style="color:#D43324">case</span><span style="color:#D43324"> var</span><span style="color:#222222"> response?) {</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#11796D"> 'Could not complete upload to </span><span style="color:#11796D">${</span><span style="color:#222222">response</span><span style="color:#11796D">.</span><span style="color:#222222">url</span><span style="color:#11796D">}</span><span style="color:#11796D"> '</span></span> <span class="line"><span style="color:#11796D"> '(error code </span><span style="color:#11796D">${</span><span style="color:#222222">response</span><span style="color:#11796D">.</span><span style="color:#222222">errorCode</span><span style="color:#11796D">}</span><span style="color:#11796D">): </span><span style="color:#11796D">${</span><span style="color:#222222">response</span><span style="color:#11796D">.</span><span style="color:#222222">reason</span><span style="color:#11796D">}</span><span style="color:#11796D">.'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#11796D"> 'Could not upload (no response).'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Another work around is to assign the field's value to a local variable. Null checks on that variable will promote, so you can safely treat it as non-nullable.</p> <?code-excerpt "usage_good.dart (shadow-nullable-field)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> UploadException</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> final</span><span style="color:#0468D7"> Response</span><span style="color:#222222">? response;</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> UploadException</span><span style="color:#222222">([</span><span style="color:#D43324">this</span><span style="color:#222222">.response]);</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> @override</span></span> <span class="line"><span style="color:#0468D7"> String</span><span style="color:#6200EE"> toString</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#D43324"> final</span><span style="color:#222222"> response = </span><span style="color:#D43324">this</span><span style="color:#222222">.response;</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (response != </span><span style="color:#11796D">null</span><span style="color:#222222">) {</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#11796D"> 'Could not complete upload to </span><span style="color:#11796D">${</span><span style="color:#222222">response</span><span style="color:#11796D">.</span><span style="color:#222222">url</span><span style="color:#11796D">}</span><span style="color:#11796D"> '</span></span> <span class="line"><span style="color:#11796D"> '(error code </span><span style="color:#11796D">${</span><span style="color:#222222">response</span><span style="color:#11796D">.</span><span style="color:#222222">errorCode</span><span style="color:#11796D">}</span><span style="color:#11796D">): </span><span style="color:#11796D">${</span><span style="color:#222222">response</span><span style="color:#11796D">.</span><span style="color:#222222">reason</span><span style="color:#11796D">}</span><span style="color:#11796D">.'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#11796D"> 'Could not upload (no response).'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Be careful when using a local variable. If you need to write back to the field, make sure that you don't write back to the local variable instead. (Making the local variable <a href="/effective-dart/usage#do-follow-a-consistent-rule-for-var-and-final-on-local-variables"><code>final</code></a> can prevent such mistakes.) Also, if the field might change while the local is still in scope, then the local might have a stale value.</p><p>Sometimes it's best to simply <a href="/null-safety/understanding-null-safety#non-null-assertion-operator">use <code>!</code></a> on the field. In some cases, though, using either a local variable or a null-check pattern can be cleaner and safer than using <code>!</code> every time you need to treat the value as non-null:</p> <?code-excerpt "usage_bad.dart (shadow-nullable-field)" replace="/!\./[!!!]./g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> UploadException</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> final</span><span style="color:#0468D7"> Response</span><span style="color:#222222">? response;</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> UploadException</span><span style="color:#222222">([</span><span style="color:#D43324">this</span><span style="color:#222222">.response]);</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> @override</span></span> <span class="line"><span style="color:#0468D7"> String</span><span style="color:#6200EE"> toString</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (response != </span><span style="color:#11796D">null</span><span style="color:#222222">) {</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#11796D"> 'Could not complete upload to </span><span style="color:#11796D">${</span><span style="color:#222222">response</span><mark class="highlight"><span style="color:#11796D">!</span></mark><span style="color:#11796D">.</span><span style="color:#222222">url</span><span style="color:#11796D">}</span><span style="color:#11796D"> '</span></span> <span class="line"><span style="color:#11796D"> '(error code </span><span style="color:#11796D">${</span><span style="color:#222222">response</span><mark class="highlight"><span style="color:#11796D">!</span></mark><span style="color:#11796D">.</span><span style="color:#222222">errorCode</span><span style="color:#11796D">}</span><span style="color:#11796D">): </span><span style="color:#11796D">${</span><span style="color:#222222">response</span><mark class="highlight"><span style="color:#11796D">!</span></mark><span style="color:#11796D">.</span><span style="color:#222222">reason</span><span style="color:#11796D">}</span><span style="color:#11796D">.'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#11796D"> 'Could not upload (no response).'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h2 id="strings">Strings</h2><a class="heading-link" href="#strings" aria-label="Link to 'Strings' section">#</a></div><p>Here are some best practices to keep in mind when composing strings in Dart.</p><div class="header-wrapper"><h3 id="do-use-adjacent-strings-to-concatenate-string-literals">DO use adjacent strings to concatenate string literals</h3><a class="heading-link" href="#do-use-adjacent-strings-to-concatenate-string-literals" aria-label="Link to 'DO use adjacent strings to concatenate string literals' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/prefer_adjacent_string_concatenation">prefer_adjacent_string_concatenation</a></p><p>If you have two string literals—not values, but the actual quoted literal form—you do not need to use <code>+</code> to concatenate them. Just like in C and C++, simply placing them next to each other does it. This is a good way to make a single long string that doesn't fit on one line.</p> <?code-excerpt "usage_good.dart (adjacent-strings-literals)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#6200EE">raiseAlarm</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#11796D"> 'ERROR: Parts of the spaceship are on fire. Other '</span></span> <span class="line"><span style="color:#11796D"> 'parts are overrun by martians. Unclear which are which.'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222">);</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (adjacent-strings-literals)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#6200EE">raiseAlarm</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#11796D"> 'ERROR: Parts of the spaceship are on fire. Other '</span><span style="color:#222222"> +</span></span> <span class="line"><span style="color:#11796D"> 'parts are overrun by martians. Unclear which are which.'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222">);</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="prefer-using-interpolation-to-compose-strings-and-values">PREFER using interpolation to compose strings and values</h3><a class="heading-link" href="#prefer-using-interpolation-to-compose-strings-and-values" aria-label="Link to 'PREFER using interpolation to compose strings and values' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/prefer_interpolation_to_compose_strings">prefer_interpolation_to_compose_strings</a></p><p>If you're coming from other languages, you're used to using long chains of <code>+</code> to build a string out of literals and other values. That does work in Dart, but it's almost always cleaner and shorter to use interpolation:</p> <?code-excerpt "usage_good.dart (string-interpolation)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#11796D">'Hello, </span><span style="color:#11796D">$</span><span style="color:#222222">name</span><span style="color:#11796D">! You are </span><span style="color:#11796D">${</span><span style="color:#222222">year</span><span style="color:#11796D"> - </span><span style="color:#222222">birth</span><span style="color:#11796D">}</span><span style="color:#11796D"> years old.'</span><span style="color:#222222">;</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (string-interpolation)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#11796D">'Hello, '</span><span style="color:#222222"> + name + </span><span style="color:#11796D">'! You are '</span><span style="color:#222222"> + (year - birth).</span><span style="color:#6200EE">toString</span><span style="color:#222222">() + </span><span style="color:#11796D">' y...'</span><span style="color:#222222">;</span></span></code></pre></div></div><p>Note that this guideline applies to combining <em>multiple</em> literals and values. It's fine to use <code>.toString()</code> when converting only a single object to a string.</p><div class="header-wrapper"><h3 id="avoid-using-curly-braces-in-interpolation-when-not-needed">AVOID using curly braces in interpolation when not needed</h3><a class="heading-link" href="#avoid-using-curly-braces-in-interpolation-when-not-needed" aria-label="Link to 'AVOID using curly braces in interpolation when not needed' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/unnecessary_brace_in_string_interps">unnecessary_brace_in_string_interps</a></p><p>If you're interpolating a simple identifier not immediately followed by more alphanumeric text, the <code>{}</code> should be omitted.</p> <?code-excerpt "usage_good.dart (string-interpolation-avoid-curly)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> greeting = </span><span style="color:#11796D">'Hi, </span><span style="color:#11796D">$</span><span style="color:#222222">name</span><span style="color:#11796D">! I love your </span><span style="color:#11796D">${</span><span style="color:#222222">decade</span><span style="color:#11796D">}</span><span style="color:#11796D">s costume.'</span><span style="color:#222222">;</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (string-interpolation-avoid-curly)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> greeting = </span><span style="color:#11796D">'Hi, </span><span style="color:#11796D">${</span><span style="color:#222222">name</span><span style="color:#11796D">}</span><span style="color:#11796D">! I love your </span><span style="color:#11796D">${</span><span style="color:#222222">decade</span><span style="color:#11796D">}</span><span style="color:#11796D">s costume.'</span><span style="color:#222222">;</span></span></code></pre></div></div><div class="header-wrapper"><h2 id="collections">Collections</h2><a class="heading-link" href="#collections" aria-label="Link to 'Collections' section">#</a></div><p>Out of the box, Dart supports four collection types: lists, maps, queues, and sets. The following best practices apply to collections.</p><div class="header-wrapper"><h3 id="do-use-collection-literals-when-possible">DO use collection literals when possible</h3><a class="heading-link" href="#do-use-collection-literals-when-possible" aria-label="Link to 'DO use collection literals when possible' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/prefer_collection_literals">prefer_collection_literals</a></p><p>Dart has three core collection types: List, Map, and Set. The Map and Set classes have unnamed constructors like most classes do. But because these collections are used so frequently, Dart has nicer built-in syntax for creating them:</p> <?code-excerpt "usage_good.dart (collection-literals)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> points = <</span><span style="color:#0468D7">Point</span><span style="color:#222222">>[];</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> addresses = <</span><span style="color:#0468D7">String</span><span style="color:#222222">, </span><span style="color:#0468D7">Address</span><span style="color:#222222">>{};</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> counts = <</span><span style="color:#0468D7">int</span><span style="color:#222222">>{};</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (collection-literals)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> addresses = </span><span style="color:#0468D7">Map</span><span style="color:#222222"><</span><span style="color:#0468D7">String</span><span style="color:#222222">, </span><span style="color:#0468D7">Address</span><span style="color:#222222">>();</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> counts = </span><span style="color:#0468D7">Set</span><span style="color:#222222"><</span><span style="color:#0468D7">int</span><span style="color:#222222">>();</span></span></code></pre></div></div><p>Note that this guideline doesn't apply to the <em>named</em> constructors for those classes. <code>List.from()</code>, <code>Map.fromIterable()</code>, and friends all have their uses. (The List class also has an unnamed constructor, but it is prohibited in null safe Dart.)</p><p>Collection literals are particularly powerful in Dart because they give you access to the <a href="/language/collections#spread-operators">spread operator</a> for including the contents of other collections, and <a href="/language/collections#control-flow-operators"><code>if</code> and <code>for</code></a> for performing control flow while building the contents:</p> <?code-excerpt "usage_good.dart (spread-etc)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> arguments = [</span></span> <span class="line"><span style="color:#222222"> ...options,</span></span> <span class="line"><span style="color:#222222"> command,</span></span> <span class="line"><span style="color:#222222"> ...?modeFlags,</span></span> <span class="line"><span style="color:#D43324"> for</span><span style="color:#222222"> (</span><span style="color:#D43324">var</span><span style="color:#222222"> path </span><span style="color:#D43324">in</span><span style="color:#222222"> filePaths)</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (path.</span><span style="color:#6200EE">endsWith</span><span style="color:#222222">(</span><span style="color:#11796D">'.dart'</span><span style="color:#222222">)) path.</span><span style="color:#6200EE">replaceAll</span><span style="color:#222222">(</span><span style="color:#11796D">'.dart'</span><span style="color:#222222">, </span><span style="color:#11796D">'.js'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222">];</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (spread-etc)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> arguments = <</span><span style="color:#0468D7">String</span><span style="color:#222222">>[];</span></span> <span class="line"><span style="color:#222222">arguments.</span><span style="color:#6200EE">addAll</span><span style="color:#222222">(options);</span></span> <span class="line"><span style="color:#222222">arguments.</span><span style="color:#6200EE">add</span><span style="color:#222222">(command);</span></span> <span class="line"><span style="color:#D43324">if</span><span style="color:#222222"> (modeFlags != </span><span style="color:#11796D">null</span><span style="color:#222222">) arguments.</span><span style="color:#6200EE">addAll</span><span style="color:#222222">(modeFlags);</span></span> <span class="line"><span style="color:#222222">arguments.</span><span style="color:#6200EE">addAll</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> filePaths</span></span> <span class="line"><span style="color:#222222"> .</span><span style="color:#6200EE">where</span><span style="color:#222222">((path) => path.</span><span style="color:#6200EE">endsWith</span><span style="color:#222222">(</span><span style="color:#11796D">'.dart'</span><span style="color:#222222">))</span></span> <span class="line"><span style="color:#222222"> .</span><span style="color:#6200EE">map</span><span style="color:#222222">((path) => path.</span><span style="color:#6200EE">replaceAll</span><span style="color:#222222">(</span><span style="color:#11796D">'.dart'</span><span style="color:#222222">, </span><span style="color:#11796D">'.js'</span><span style="color:#222222">)),</span></span> <span class="line"><span style="color:#222222">);</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="dont-use-length-to-see-if-a-collection-is-empty">DON'T use <code>.length</code> to see if a collection is empty</h3><a class="heading-link" href="#dont-use-length-to-see-if-a-collection-is-empty" aria-label="Link to 'DON'T use .length to see if a collection is empty' section">#</a></div><p class="linter-rule">Linter rules: <a href="/tools/linter-rules/prefer_is_empty">prefer_is_empty</a>, <a href="/tools/linter-rules/prefer_is_not_empty">prefer_is_not_empty</a></p><p>The <a href="https://api.dart.dev/dart-core/Iterable-class.html">Iterable</a> contract does not require that a collection know its length or be able to provide it in constant time. Calling <code>.length</code> just to see if the collection contains <em>anything</em> can be painfully slow.</p><p>Instead, there are faster and more readable getters: <code>.isEmpty</code> and <code>.isNotEmpty</code>. Use the one that doesn't require you to negate the result.</p> <?code-excerpt "usage_good.dart (dont-use-length)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">if</span><span style="color:#222222"> (lunchBox.isEmpty) </span><span style="color:#D43324">return</span><span style="color:#11796D"> 'so hungry...'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#D43324">if</span><span style="color:#222222"> (words.isNotEmpty) </span><span style="color:#D43324">return</span><span style="color:#222222"> words.</span><span style="color:#6200EE">join</span><span style="color:#222222">(</span><span style="color:#11796D">' '</span><span style="color:#222222">);</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (dont-use-length)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">if</span><span style="color:#222222"> (lunchBox.length == </span><span style="color:#11796D">0</span><span style="color:#222222">) </span><span style="color:#D43324">return</span><span style="color:#11796D"> 'so hungry...'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#D43324">if</span><span style="color:#222222"> (!words.isEmpty) </span><span style="color:#D43324">return</span><span style="color:#222222"> words.</span><span style="color:#6200EE">join</span><span style="color:#222222">(</span><span style="color:#11796D">' '</span><span style="color:#222222">);</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="avoid-using-iterable-foreach-with-a-function-literal">AVOID using <code>Iterable.forEach()</code> with a function literal</h3><a class="heading-link" href="#avoid-using-iterable-foreach-with-a-function-literal" aria-label="Link to 'AVOID using Iterable.forEach() with a function literal' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/avoid_function_literals_in_foreach_calls">avoid_function_literals_in_foreach_calls</a></p><p><code>forEach()</code> functions are widely used in JavaScript because the built in <code>for-in</code> loop doesn't do what you usually want. In Dart, if you want to iterate over a sequence, the idiomatic way to do that is using a loop.</p> <?code-excerpt "usage_good.dart (avoid-for-each)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">for</span><span style="color:#222222"> (</span><span style="color:#D43324">final</span><span style="color:#222222"> person </span><span style="color:#D43324">in</span><span style="color:#222222"> people) {</span></span> <span class="line"><span style="color:#222222"> ...</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (avoid-for-each)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#222222">people.</span><span style="color:#6200EE">forEach</span><span style="color:#222222">((person) {</span></span> <span class="line"><span style="color:#222222"> ...</span></span> <span class="line"><span style="color:#222222">});</span></span></code></pre></div></div><p>Note that this guideline specifically says "function <em>literal</em>". If you want to invoke some <em>already existing</em> function on each element, <code>forEach()</code> is fine.</p> <?code-excerpt "usage_good.dart (forEach-over-func)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#222222">people.</span><span style="color:#6200EE">forEach</span><span style="color:#222222">(print);</span></span></code></pre></div></div><p>Also note that it's always OK to use <code>Map.forEach()</code>. Maps aren't iterable, so this guideline doesn't apply.</p><div class="header-wrapper"><h3 id="dont-use-list-from-unless-you-intend-to-change-the-type-of-the-result">DON'T use <code>List.from()</code> unless you intend to change the type of the result</h3><a class="heading-link" href="#dont-use-list-from-unless-you-intend-to-change-the-type-of-the-result" aria-label="Link to 'DON'T use List.from() unless you intend to change the type of the result' section">#</a></div><p>Given an Iterable, there are two obvious ways to produce a new List that contains the same elements:</p> <?code-excerpt "../../test/effective_dart_test.dart (list-from-1)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> copy1 = iterable.</span><span style="color:#6200EE">toList</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> copy2 = </span><span style="color:#0468D7">List</span><span style="color:#222222">.</span><span style="color:#6200EE">from</span><span style="color:#222222">(iterable);</span></span></code></pre></div></div><p>The obvious difference is that the first one is shorter. The <em>important</em> difference is that the first one preserves the type argument of the original object:</p> <?code-excerpt "../../test/effective_dart_test.dart (list-from-good)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#6E6E70">// Creates a List<int>:</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> iterable = [</span><span style="color:#11796D">1</span><span style="color:#222222">, </span><span style="color:#11796D">2</span><span style="color:#222222">, </span><span style="color:#11796D">3</span><span style="color:#222222">];</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">// Prints "List<int>":</span></span> <span class="line"><span style="color:#6200EE">print</span><span style="color:#222222">(iterable.</span><span style="color:#6200EE">toList</span><span style="color:#222222">().runtimeType);</span></span></code></pre></div></div><?code-excerpt "../../test/effective_dart_test.dart (list-from-bad)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#6E6E70">// Creates a List<int>:</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> iterable = [</span><span style="color:#11796D">1</span><span style="color:#222222">, </span><span style="color:#11796D">2</span><span style="color:#222222">, </span><span style="color:#11796D">3</span><span style="color:#222222">];</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">// Prints "List<dynamic>":</span></span> <span class="line"><span style="color:#6200EE">print</span><span style="color:#222222">(</span><span style="color:#0468D7">List</span><span style="color:#222222">.</span><span style="color:#6200EE">from</span><span style="color:#222222">(iterable).runtimeType);</span></span></code></pre></div></div><p>If you <em>want</em> to change the type, then calling <code>List.from()</code> is useful:</p> <?code-excerpt "../../test/effective_dart_test.dart (list-from-3)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> numbers = [</span><span style="color:#11796D">1</span><span style="color:#222222">, </span><span style="color:#11796D">2.3</span><span style="color:#222222">, </span><span style="color:#11796D">4</span><span style="color:#222222">]; </span><span style="color:#6E6E70">// List<num>.</span></span> <span class="line"><span style="color:#222222">numbers.</span><span style="color:#6200EE">removeAt</span><span style="color:#222222">(</span><span style="color:#11796D">1</span><span style="color:#222222">); </span><span style="color:#6E6E70">// Now it only contains integers.</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> ints = </span><span style="color:#0468D7">List</span><span style="color:#222222"><</span><span style="color:#0468D7">int</span><span style="color:#222222">>.</span><span style="color:#6200EE">from</span><span style="color:#222222">(numbers);</span></span></code></pre></div></div><p>But if your goal is just to copy the iterable and preserve its original type, or you don't care about the type, then use <code>toList()</code>.</p><div class="header-wrapper"><h3 id="do-use-wheretype-to-filter-a-collection-by-type">DO use <code>whereType()</code> to filter a collection by type</h3><a class="heading-link" href="#do-use-wheretype-to-filter-a-collection-by-type" aria-label="Link to 'DO use whereType() to filter a collection by type' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/prefer_iterable_whereType">prefer_iterable_whereType</a></p><p>Let's say you have a list containing a mixture of objects, and you want to get just the integers out of it. You could use <code>where()</code> like this:</p> <?code-excerpt "usage_bad.dart (where-type)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> objects = [</span><span style="color:#11796D">1</span><span style="color:#222222">, </span><span style="color:#11796D">'a'</span><span style="color:#222222">, </span><span style="color:#11796D">2</span><span style="color:#222222">, </span><span style="color:#11796D">'b'</span><span style="color:#222222">, </span><span style="color:#11796D">3</span><span style="color:#222222">];</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> ints = objects.</span><span style="color:#6200EE">where</span><span style="color:#222222">((e) => e is </span><span style="color:#0468D7">int</span><span style="color:#222222">);</span></span></code></pre></div></div><p>This is verbose, but, worse, it returns an iterable whose type probably isn't what you want. In the example here, it returns an <code>Iterable<Object></code> even though you likely want an <code>Iterable<int></code> since that's the type you're filtering it to.</p><p>Sometimes you see code that "corrects" the above error by adding <code>cast()</code>:</p> <?code-excerpt "usage_bad.dart (where-type-2)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> objects = [</span><span style="color:#11796D">1</span><span style="color:#222222">, </span><span style="color:#11796D">'a'</span><span style="color:#222222">, </span><span style="color:#11796D">2</span><span style="color:#222222">, </span><span style="color:#11796D">'b'</span><span style="color:#222222">, </span><span style="color:#11796D">3</span><span style="color:#222222">];</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> ints = objects.</span><span style="color:#6200EE">where</span><span style="color:#222222">((e) => e is </span><span style="color:#0468D7">int</span><span style="color:#222222">).</span><span style="color:#6200EE">cast</span><span style="color:#222222"><</span><span style="color:#0468D7">int</span><span style="color:#222222">>();</span></span></code></pre></div></div><p>That's verbose and causes two wrappers to be created, with two layers of indirection and redundant runtime checking. Fortunately, the core library has the <a href="https://api.dart.dev/dart-core/Iterable/whereType.html"><code>whereType()</code></a> method for this exact use case:</p> <?code-excerpt "../../test/effective_dart_test.dart (where-type)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> objects = [</span><span style="color:#11796D">1</span><span style="color:#222222">, </span><span style="color:#11796D">'a'</span><span style="color:#222222">, </span><span style="color:#11796D">2</span><span style="color:#222222">, </span><span style="color:#11796D">'b'</span><span style="color:#222222">, </span><span style="color:#11796D">3</span><span style="color:#222222">];</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> ints = objects.</span><span style="color:#6200EE">whereType</span><span style="color:#222222"><</span><span style="color:#0468D7">int</span><span style="color:#222222">>();</span></span></code></pre></div></div><p>Using <code>whereType()</code> is concise, produces an <a href="https://api.dart.dev/dart-core/Iterable-class.html">Iterable</a> of the desired type, and has no unnecessary levels of wrapping.</p><div class="header-wrapper"><h3 id="dont-use-cast-when-a-nearby-operation-will-do">DON'T use <code>cast()</code> when a nearby operation will do</h3><a class="heading-link" href="#dont-use-cast-when-a-nearby-operation-will-do" aria-label="Link to 'DON'T use cast() when a nearby operation will do' section">#</a></div><p>Often when you're dealing with an iterable or stream, you perform several transformations on it. At the end, you want to produce an object with a certain type argument. Instead of tacking on a call to <code>cast()</code>, see if one of the existing transformations can change the type.</p><p>If you're already calling <code>toList()</code>, replace that with a call to <a href="https://api.dart.dev/dart-core/List/List.from.html"><code>List<T>.from()</code></a> where <code>T</code> is the type of resulting list you want.</p> <?code-excerpt "usage_good.dart (cast-list)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> stuff = <</span><span style="color:#0468D7">dynamic</span><span style="color:#222222">>[</span><span style="color:#11796D">1</span><span style="color:#222222">, </span><span style="color:#11796D">2</span><span style="color:#222222">];</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> ints = </span><span style="color:#0468D7">List</span><span style="color:#222222"><</span><span style="color:#0468D7">int</span><span style="color:#222222">>.</span><span style="color:#6200EE">from</span><span style="color:#222222">(stuff);</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (cast-list)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> stuff = <</span><span style="color:#0468D7">dynamic</span><span style="color:#222222">>[</span><span style="color:#11796D">1</span><span style="color:#222222">, </span><span style="color:#11796D">2</span><span style="color:#222222">];</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> ints = stuff.</span><span style="color:#6200EE">toList</span><span style="color:#222222">().</span><span style="color:#6200EE">cast</span><span style="color:#222222"><</span><span style="color:#0468D7">int</span><span style="color:#222222">>();</span></span></code></pre></div></div><p>If you are calling <code>map()</code>, give it an explicit type argument so that it produces an iterable of the desired type. Type inference often picks the correct type for you based on the function you pass to <code>map()</code>, but sometimes you need to be explicit.</p> <?code-excerpt "usage_good.dart (cast-map)" replace="/\(n as int\)/n/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> stuff = <</span><span style="color:#0468D7">dynamic</span><span style="color:#222222">>[</span><span style="color:#11796D">1</span><span style="color:#222222">, </span><span style="color:#11796D">2</span><span style="color:#222222">];</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> reciprocals = stuff.</span><span style="color:#6200EE">map</span><span style="color:#222222"><</span><span style="color:#0468D7">double</span><span style="color:#222222">>((n) => </span><span style="color:#11796D">1</span><span style="color:#222222"> / n);</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (cast-map)" replace="/\(n as int\)/n/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> stuff = <</span><span style="color:#0468D7">dynamic</span><span style="color:#222222">>[</span><span style="color:#11796D">1</span><span style="color:#222222">, </span><span style="color:#11796D">2</span><span style="color:#222222">];</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> reciprocals = stuff.</span><span style="color:#6200EE">map</span><span style="color:#222222">((n) => </span><span style="color:#11796D">1</span><span style="color:#222222"> / n).</span><span style="color:#6200EE">cast</span><span style="color:#222222"><</span><span style="color:#0468D7">double</span><span style="color:#222222">>();</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="avoid-using-cast">AVOID using <code>cast()</code></h3><a class="heading-link" href="#avoid-using-cast" aria-label="Link to 'AVOID using cast()' section">#</a></div><p>This is the softer generalization of the previous rule. Sometimes there is no nearby operation you can use to fix the type of some object. Even then, when possible avoid using <code>cast()</code> to "change" a collection's type.</p><p>Prefer any of these options instead:</p><ul><li><p><strong>Create it with the right type.</strong> Change the code where the collection is first created so that it has the right type.</p></li><li><p><strong>Cast the elements on access.</strong> If you immediately iterate over the collection, cast each element inside the iteration.</p></li><li><p><strong>Eagerly cast using <code>List.from()</code>.</strong> If you'll eventually access most of the elements in the collection, and you don't need the object to be backed by the original live object, convert it using <code>List.from()</code>.</p><p>The <code>cast()</code> method returns a lazy collection that checks the element type on <em>every operation</em>. If you perform only a few operations on only a few elements, that laziness can be good. But in many cases, the overhead of lazy validation and of wrapping outweighs the benefits.</p></li></ul><p>Here is an example of <strong>creating it with the right type:</strong></p> <?code-excerpt "usage_good.dart (cast-at-create)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">List</span><span style="color:#222222"><</span><span style="color:#0468D7">int</span><span style="color:#222222">> </span><span style="color:#6200EE">singletonList</span><span style="color:#222222">(</span><span style="color:#0468D7">int</span><span style="color:#222222"> value) {</span></span> <span class="line"><span style="color:#D43324"> var</span><span style="color:#222222"> list = <</span><span style="color:#0468D7">int</span><span style="color:#222222">>[];</span></span> <span class="line"><span style="color:#222222"> list.</span><span style="color:#6200EE">add</span><span style="color:#222222">(value);</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> list;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (cast-at-create)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">List</span><span style="color:#222222"><</span><span style="color:#0468D7">int</span><span style="color:#222222">> </span><span style="color:#6200EE">singletonList</span><span style="color:#222222">(</span><span style="color:#0468D7">int</span><span style="color:#222222"> value) {</span></span> <span class="line"><span style="color:#D43324"> var</span><span style="color:#222222"> list = []; </span><span style="color:#6E6E70">// List<dynamic>.</span></span> <span class="line"><span style="color:#222222"> list.</span><span style="color:#6200EE">add</span><span style="color:#222222">(value);</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> list.</span><span style="color:#6200EE">cast</span><span style="color:#222222"><</span><span style="color:#0468D7">int</span><span style="color:#222222">>();</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Here is <strong>casting each element on access:</strong></p> <?code-excerpt "usage_good.dart (cast-iterate)" replace="/\(n as int\)/[!$&!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> printEvens</span><span style="color:#222222">(</span><span style="color:#0468D7">List</span><span style="color:#222222"><</span><span style="color:#0468D7">Object</span><span style="color:#222222">> objects) {</span></span> <span class="line"><span style="color:#6E6E70"> // We happen to know the list only contains ints.</span></span> <span class="line"><span style="color:#D43324"> for</span><span style="color:#222222"> (</span><span style="color:#D43324">final</span><span style="color:#222222"> n </span><span style="color:#D43324">in</span><span style="color:#222222"> objects) {</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (</span><mark class="highlight"><span style="color:#222222">(n </span><span style="color:#D43324">as</span><span style="color:#0468D7"> int</span><span style="color:#222222">)</span></mark><span style="color:#222222">.isEven) </span><span style="color:#6200EE">print</span><span style="color:#222222">(n);</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (cast-iterate)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> printEvens</span><span style="color:#222222">(</span><span style="color:#0468D7">List</span><span style="color:#222222"><</span><span style="color:#0468D7">Object</span><span style="color:#222222">> objects) {</span></span> <span class="line"><span style="color:#6E6E70"> // We happen to know the list only contains ints.</span></span> <span class="line"><span style="color:#D43324"> for</span><span style="color:#222222"> (</span><span style="color:#D43324">final</span><span style="color:#222222"> n </span><span style="color:#D43324">in</span><span style="color:#222222"> objects.</span><span style="color:#6200EE">cast</span><span style="color:#222222"><</span><span style="color:#0468D7">int</span><span style="color:#222222">>()) {</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (n.isEven) </span><span style="color:#6200EE">print</span><span style="color:#222222">(n);</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Here is <strong>casting eagerly using <code>List.from()</code>:</strong></p> <?code-excerpt "usage_good.dart (cast-from)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">int</span><span style="color:#6200EE"> median</span><span style="color:#222222">(</span><span style="color:#0468D7">List</span><span style="color:#222222"><</span><span style="color:#0468D7">Object</span><span style="color:#222222">> objects) {</span></span> <span class="line"><span style="color:#6E6E70"> // We happen to know the list only contains ints.</span></span> <span class="line"><span style="color:#D43324"> var</span><span style="color:#222222"> ints = </span><span style="color:#0468D7">List</span><span style="color:#222222"><</span><span style="color:#0468D7">int</span><span style="color:#222222">>.</span><span style="color:#6200EE">from</span><span style="color:#222222">(objects);</span></span> <span class="line"><span style="color:#222222"> ints.</span><span style="color:#6200EE">sort</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> ints[ints.length ~/ </span><span style="color:#11796D">2</span><span style="color:#222222">];</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (cast-from)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">int</span><span style="color:#6200EE"> median</span><span style="color:#222222">(</span><span style="color:#0468D7">List</span><span style="color:#222222"><</span><span style="color:#0468D7">Object</span><span style="color:#222222">> objects) {</span></span> <span class="line"><span style="color:#6E6E70"> // We happen to know the list only contains ints.</span></span> <span class="line"><span style="color:#D43324"> var</span><span style="color:#222222"> ints = objects.</span><span style="color:#6200EE">cast</span><span style="color:#222222"><</span><span style="color:#0468D7">int</span><span style="color:#222222">>();</span></span> <span class="line"><span style="color:#222222"> ints.</span><span style="color:#6200EE">sort</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> ints[ints.length ~/ </span><span style="color:#11796D">2</span><span style="color:#222222">];</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>These alternatives don't always work, of course, and sometimes <code>cast()</code> is the right answer. But consider that method a little risky and undesirable—it can be slow and may fail at runtime if you aren't careful.</p><div class="header-wrapper"><h2 id="functions">Functions</h2><a class="heading-link" href="#functions" aria-label="Link to 'Functions' section">#</a></div><p>In Dart, even functions are objects. Here are some best practices involving functions.</p><div class="header-wrapper"><h3 id="do-use-a-function-declaration-to-bind-a-function-to-a-name">DO use a function declaration to bind a function to a name</h3><a class="heading-link" href="#do-use-a-function-declaration-to-bind-a-function-to-a-name" aria-label="Link to 'DO use a function declaration to bind a function to a name' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/prefer_function_declarations_over_variables">prefer_function_declarations_over_variables</a></p><p>Modern languages have realized how useful local nested functions and closures are. It's common to have a function defined inside another one. In many cases, this function is used as a callback immediately and doesn't need a name. A function expression is great for that.</p><p>But, if you do need to give it a name, use a function declaration statement instead of binding a lambda to a variable.</p> <?code-excerpt "usage_good.dart (func-decl)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> localFunction</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#222222"> ...</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (func-decl)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#D43324"> var</span><span style="color:#222222"> localFunction = () {</span></span> <span class="line"><span style="color:#222222"> ...</span></span> <span class="line"><span style="color:#222222"> };</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="dont-create-a-lambda-when-a-tear-off-will-do">DON'T create a lambda when a tear-off will do</h3><a class="heading-link" href="#dont-create-a-lambda-when-a-tear-off-will-do" aria-label="Link to 'DON'T create a lambda when a tear-off will do' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/unnecessary_lambdas">unnecessary_lambdas</a></p><p>When you refer to a function, method, or named constructor without parentheses, Dart creates a <em>tear-off</em>. This is a closure that takes the same parameters as the function and invokes the underlying function when you call it. If your code needs a closure that invokes a named function with the same parameters as the closure accepts, don't wrap the call in a lambda. Use a tear-off.</p> <?code-excerpt "usage_good.dart (use-tear-off)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> charCodes = [</span><span style="color:#11796D">68</span><span style="color:#222222">, </span><span style="color:#11796D">97</span><span style="color:#222222">, </span><span style="color:#11796D">114</span><span style="color:#222222">, </span><span style="color:#11796D">116</span><span style="color:#222222">];</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> buffer = </span><span style="color:#0468D7">StringBuffer</span><span style="color:#222222">();</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">// Function:</span></span> <span class="line"><span style="color:#222222">charCodes.</span><span style="color:#6200EE">forEach</span><span style="color:#222222">(print);</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">// Method:</span></span> <span class="line"><span style="color:#222222">charCodes.</span><span style="color:#6200EE">forEach</span><span style="color:#222222">(buffer.write);</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">// Named constructor:</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> strings = charCodes.</span><span style="color:#6200EE">map</span><span style="color:#222222">(</span><span style="color:#0468D7">String</span><span style="color:#222222">.fromCharCode);</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">// Unnamed constructor:</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> buffers = charCodes.</span><span style="color:#6200EE">map</span><span style="color:#222222">(</span><span style="color:#0468D7">StringBuffer</span><span style="color:#222222">.</span><span style="color:#D43324">new</span><span style="color:#222222">);</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (use-tear-off)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> charCodes = [</span><span style="color:#11796D">68</span><span style="color:#222222">, </span><span style="color:#11796D">97</span><span style="color:#222222">, </span><span style="color:#11796D">114</span><span style="color:#222222">, </span><span style="color:#11796D">116</span><span style="color:#222222">];</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> buffer = </span><span style="color:#0468D7">StringBuffer</span><span style="color:#222222">();</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">// Function:</span></span> <span class="line"><span style="color:#222222">charCodes.</span><span style="color:#6200EE">forEach</span><span style="color:#222222">((code) {</span></span> <span class="line"><span style="color:#6200EE"> print</span><span style="color:#222222">(code);</span></span> <span class="line"><span style="color:#222222">});</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">// Method:</span></span> <span class="line"><span style="color:#222222">charCodes.</span><span style="color:#6200EE">forEach</span><span style="color:#222222">((code) {</span></span> <span class="line"><span style="color:#222222"> buffer.</span><span style="color:#6200EE">write</span><span style="color:#222222">(code);</span></span> <span class="line"><span style="color:#222222">});</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">// Named constructor:</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> strings = charCodes.</span><span style="color:#6200EE">map</span><span style="color:#222222">((code) => </span><span style="color:#0468D7">String</span><span style="color:#222222">.</span><span style="color:#6200EE">fromCharCode</span><span style="color:#222222">(code));</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">// Unnamed constructor:</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> buffers = charCodes.</span><span style="color:#6200EE">map</span><span style="color:#222222">((code) => </span><span style="color:#0468D7">StringBuffer</span><span style="color:#222222">(code));</span></span></code></pre></div></div><div class="header-wrapper"><h2 id="variables">Variables</h2><a class="heading-link" href="#variables" aria-label="Link to 'Variables' section">#</a></div><p>The following best practices describe how to best use variables in Dart.</p><div class="header-wrapper"><h3 id="do-follow-a-consistent-rule-for-var-and-final-on-local-variables">DO follow a consistent rule for <code>var</code> and <code>final</code> on local variables</h3><a class="heading-link" href="#do-follow-a-consistent-rule-for-var-and-final-on-local-variables" aria-label="Link to 'DO follow a consistent rule for var and final on local variables' section">#</a></div><p>Most local variables shouldn't have type annotations and should be declared using just <code>var</code> or <code>final</code>. There are two rules in wide use for when to use one or the other:</p><ul><li><p>Use <code>final</code> for local variables that are not reassigned and <code>var</code> for those that are.</p></li><li><p>Use <code>var</code> for all local variables, even ones that aren't reassigned. Never use <code>final</code> for locals. (Using <code>final</code> for fields and top-level variables is still encouraged, of course.)</p></li></ul><p>Either rule is acceptable, but pick <em>one</em> and apply it consistently throughout your code. That way when a reader sees <code>var</code>, they know whether it means that the variable is assigned later in the function.</p><div class="header-wrapper"><h3 id="avoid-storing-what-you-can-calculate">AVOID storing what you can calculate</h3><a class="heading-link" href="#avoid-storing-what-you-can-calculate" aria-label="Link to 'AVOID storing what you can calculate' section">#</a></div><p>When designing a class, you often want to expose multiple views into the same underlying state. Often you see code that calculates all of those views in the constructor and then stores them:</p> <?code-excerpt "usage_bad.dart (calc-vs-store1)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Circle</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#0468D7"> double</span><span style="color:#222222"> radius;</span></span> <span class="line"><span style="color:#0468D7"> double</span><span style="color:#222222"> area;</span></span> <span class="line"><span style="color:#0468D7"> double</span><span style="color:#222222"> circumference;</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> Circle</span><span style="color:#222222">(</span><span style="color:#0468D7">double</span><span style="color:#222222"> radius)</span></span> <span class="line"><span style="color:#222222"> : radius = radius,</span></span> <span class="line"><span style="color:#222222"> area = pi * radius * radius,</span></span> <span class="line"><span style="color:#222222"> circumference = pi * </span><span style="color:#11796D">2.0</span><span style="color:#222222"> * radius;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>This code has two things wrong with it. First, it's likely wasting memory. The area and circumference, strictly speaking, are <em>caches</em>. They are stored calculations that we could recalculate from other data we already have. They are trading increased memory for reduced CPU usage. Do we know we have a performance problem that merits that trade-off?</p><p>Worse, the code is <em>wrong</em>. The problem with caches is <em>invalidation</em>—how do you know when the cache is out of date and needs to be recalculated? Here, we never do, even though <code>radius</code> is mutable. You can assign a different value and the <code>area</code> and <code>circumference</code> will retain their previous, now incorrect values.</p><p>To correctly handle cache invalidation, we would need to do this:</p> <?code-excerpt "usage_bad.dart (calc-vs-store2)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Circle</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#0468D7"> double</span><span style="color:#222222"> _radius;</span></span> <span class="line"><span style="color:#0468D7"> double</span><span style="color:#D43324"> get</span><span style="color:#222222"> radius => _radius;</span></span> <span class="line"><span style="color:#D43324"> set</span><span style="color:#6200EE"> radius</span><span style="color:#222222">(</span><span style="color:#0468D7">double</span><span style="color:#222222"> value) {</span></span> <span class="line"><span style="color:#222222"> _radius = value;</span></span> <span class="line"><span style="color:#6200EE"> _recalculate</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> double</span><span style="color:#222222"> _area = </span><span style="color:#11796D">0.0</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#0468D7"> double</span><span style="color:#D43324"> get</span><span style="color:#222222"> area => _area;</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> double</span><span style="color:#222222"> _circumference = </span><span style="color:#11796D">0.0</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#0468D7"> double</span><span style="color:#D43324"> get</span><span style="color:#222222"> circumference => _circumference;</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> Circle</span><span style="color:#222222">(</span><span style="color:#D43324">this</span><span style="color:#222222">._radius) {</span></span> <span class="line"><span style="color:#6200EE"> _recalculate</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> _recalculate</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#222222"> _area = pi * _radius * _radius;</span></span> <span class="line"><span style="color:#222222"> _circumference = pi * </span><span style="color:#11796D">2.0</span><span style="color:#222222"> * _radius;</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>That's an awful lot of code to write, maintain, debug, and read. Instead, your first implementation should be:</p> <?code-excerpt "usage_good.dart (calc-vs-store)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Circle</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#0468D7"> double</span><span style="color:#222222"> radius;</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> Circle</span><span style="color:#222222">(</span><span style="color:#D43324">this</span><span style="color:#222222">.radius);</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> double</span><span style="color:#D43324"> get</span><span style="color:#222222"> area => pi * radius * radius;</span></span> <span class="line"><span style="color:#0468D7"> double</span><span style="color:#D43324"> get</span><span style="color:#222222"> circumference => pi * </span><span style="color:#11796D">2.0</span><span style="color:#222222"> * radius;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>This code is shorter, uses less memory, and is less error-prone. It stores the minimal amount of data needed to represent the circle. There are no fields to get out of sync because there is only a single source of truth.</p><p>In some cases, you may need to cache the result of a slow calculation, but only do that after you know you have a performance problem, do it carefully, and leave a comment explaining the optimization.</p><div class="header-wrapper"><h2 id="members">Members</h2><a class="heading-link" href="#members" aria-label="Link to 'Members' section">#</a></div><p>In Dart, objects have members which can be functions (methods) or data (instance variables). The following best practices apply to an object's members.</p><div class="header-wrapper"><h3 id="dont-wrap-a-field-in-a-getter-and-setter-unnecessarily">DON'T wrap a field in a getter and setter unnecessarily</h3><a class="heading-link" href="#dont-wrap-a-field-in-a-getter-and-setter-unnecessarily" aria-label="Link to 'DON'T wrap a field in a getter and setter unnecessarily' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/unnecessary_getters_setters">unnecessary_getters_setters</a></p><p>In Java and C#, it's common to hide all fields behind getters and setters (or properties in C#), even if the implementation just forwards to the field. That way, if you ever need to do more work in those members, you can without needing to touch the call sites. This is because calling a getter method is different than accessing a field in Java, and accessing a property isn't binary-compatible with accessing a raw field in C#.</p><p>Dart doesn't have this limitation. Fields and getters/setters are completely indistinguishable. You can expose a field in a class and later wrap it in a getter and setter without having to touch any code that uses that field.</p> <?code-excerpt "usage_good.dart (dont-wrap-field)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Box</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#0468D7"> Object</span><span style="color:#222222">? contents;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (dont-wrap-field)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Box</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#0468D7"> Object</span><span style="color:#222222">? _contents;</span></span> <span class="line"><span style="color:#0468D7"> Object</span><span style="color:#222222">? </span><span style="color:#D43324">get</span><span style="color:#222222"> contents => _contents;</span></span> <span class="line"><span style="color:#D43324"> set</span><span style="color:#6200EE"> contents</span><span style="color:#222222">(</span><span style="color:#0468D7">Object</span><span style="color:#222222">? value) {</span></span> <span class="line"><span style="color:#222222"> _contents = value;</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="prefer-using-a-final-field-to-make-a-read-only-property">PREFER using a <code>final</code> field to make a read-only property</h3><a class="heading-link" href="#prefer-using-a-final-field-to-make-a-read-only-property" aria-label="Link to 'PREFER using a final field to make a read-only property' section">#</a></div><p>If you have a field that outside code should be able to see but not assign to, a simple solution that works in many cases is to simply mark it <code>final</code>.</p> <?code-excerpt "usage_good.dart (final)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Box</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> final</span><span style="color:#222222"> contents = [];</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (final)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Box</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#0468D7"> Object</span><span style="color:#222222">? _contents;</span></span> <span class="line"><span style="color:#0468D7"> Object</span><span style="color:#222222">? </span><span style="color:#D43324">get</span><span style="color:#222222"> contents => _contents;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Of course, if you need to internally assign to the field outside of the constructor, you may need to do the "private field, public getter" pattern, but don't reach for that until you need to.</p><div class="header-wrapper"><h3 id="consider-using-for-simple-members">CONSIDER using <code>=></code> for simple members</h3><a class="heading-link" href="#consider-using-for-simple-members" aria-label="Link to 'CONSIDER using => for simple members' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/prefer_expression_function_bodies">prefer_expression_function_bodies</a></p><p>In addition to using <code>=></code> for function expressions, Dart also lets you define members with it. That style is a good fit for simple members that just calculate and return a value.</p> <?code-excerpt "usage_good.dart (use-arrow)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">double</span><span style="color:#D43324"> get</span><span style="color:#222222"> area => (right - left) * (bottom - top);</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7">String</span><span style="color:#6200EE"> capitalize</span><span style="color:#222222">(</span><span style="color:#0468D7">String</span><span style="color:#222222"> name) =></span></span> <span class="line"><span style="color:#11796D"> '</span><span style="color:#11796D">${</span><span style="color:#222222">name</span><span style="color:#11796D">[0].</span><span style="color:#6200EE">toUpperCase</span><span style="color:#11796D">()}${</span><span style="color:#222222">name</span><span style="color:#11796D">.</span><span style="color:#6200EE">substring</span><span style="color:#11796D">(1)}</span><span style="color:#11796D">'</span><span style="color:#222222">;</span></span></code></pre></div></div><p>People <em>writing</em> code seem to love <code>=></code>, but it's very easy to abuse it and end up with code that's hard to <em>read</em>. If your declaration is more than a couple of lines or contains deeply nested expressions—cascades and conditional operators are common offenders—do yourself and everyone who has to read your code a favor and use a block body and some statements.</p> <?code-excerpt "usage_good.dart (arrow-long)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Treasure</span><span style="color:#222222">? </span><span style="color:#6200EE">openChest</span><span style="color:#222222">(</span><span style="color:#0468D7">Chest</span><span style="color:#222222"> chest, </span><span style="color:#0468D7">Point</span><span style="color:#222222"> where) {</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (_opened.</span><span style="color:#6200EE">containsKey</span><span style="color:#222222">(chest)) </span><span style="color:#D43324">return</span><span style="color:#11796D"> null</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> var</span><span style="color:#222222"> treasure = </span><span style="color:#0468D7">Treasure</span><span style="color:#222222">(where);</span></span> <span class="line"><span style="color:#222222"> treasure.</span><span style="color:#6200EE">addAll</span><span style="color:#222222">(chest.contents);</span></span> <span class="line"><span style="color:#222222"> _opened[chest] = treasure;</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> treasure;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (arrow-long)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Treasure</span><span style="color:#222222">? </span><span style="color:#6200EE">openChest</span><span style="color:#222222">(</span><span style="color:#0468D7">Chest</span><span style="color:#222222"> chest, </span><span style="color:#0468D7">Point</span><span style="color:#222222"> where) =></span></span> <span class="line"><span style="color:#222222"> _opened.</span><span style="color:#6200EE">containsKey</span><span style="color:#222222">(chest)</span></span> <span class="line"><span style="color:#222222"> ? </span><span style="color:#11796D">null</span></span> <span class="line"><span style="color:#222222"> : _opened[chest] = (</span><span style="color:#0468D7">Treasure</span><span style="color:#222222">(where)..</span><span style="color:#6200EE">addAll</span><span style="color:#222222">(chest.contents));</span></span></code></pre></div></div><p>You can also use <code>=></code> on members that don't return a value. This is idiomatic when a setter is small and has a corresponding getter that uses <code>=></code>.</p> <?code-excerpt "usage_good.dart (arrow-setter)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">num</span><span style="color:#D43324"> get</span><span style="color:#222222"> x => center.x;</span></span> <span class="line"><span style="color:#D43324">set</span><span style="color:#6200EE"> x</span><span style="color:#222222">(</span><span style="color:#0468D7">num</span><span style="color:#222222"> value) => center = </span><span style="color:#0468D7">Point</span><span style="color:#222222">(value, center.y);</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="dont-use-this-when-not-needed-to-avoid-shadowing">DON'T use <code>this.</code> except to redirect to a named constructor or to avoid shadowing</h3><a class="heading-link" href="#dont-use-this-when-not-needed-to-avoid-shadowing" aria-label="Link to 'DON'T use this. except to redirect to a named constructor or to avoid shadowing' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/unnecessary_this">unnecessary_this</a></p><p>JavaScript requires an explicit <code>this.</code> to refer to members on the object whose method is currently being executed, but Dart—like C++, Java, and C#—doesn't have that limitation.</p><p>There are only two times you need to use <code>this.</code>. One is when a local variable with the same name shadows the member you want to access:</p> <?code-excerpt "usage_bad.dart (this-dot)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Box</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#0468D7"> Object</span><span style="color:#222222">? value;</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> clear</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#D43324"> this</span><span style="color:#222222">.</span><span style="color:#6200EE">update</span><span style="color:#222222">(</span><span style="color:#11796D">null</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> update</span><span style="color:#222222">(</span><span style="color:#0468D7">Object</span><span style="color:#222222">? value) {</span></span> <span class="line"><span style="color:#D43324"> this</span><span style="color:#222222">.value = value;</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "usage_good.dart (this-dot)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Box</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#0468D7"> Object</span><span style="color:#222222">? value;</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> clear</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#6200EE"> update</span><span style="color:#222222">(</span><span style="color:#11796D">null</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> update</span><span style="color:#222222">(</span><span style="color:#0468D7">Object</span><span style="color:#222222">? value) {</span></span> <span class="line"><span style="color:#D43324"> this</span><span style="color:#222222">.value = value;</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>The other time to use <code>this.</code> is when redirecting to a named constructor:</p> <?code-excerpt "usage_bad.dart (this-dot-constructor)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> ShadeOfGray</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> final</span><span style="color:#0468D7"> int</span><span style="color:#222222"> brightness;</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> ShadeOfGray</span><span style="color:#222222">(</span><span style="color:#0468D7">int</span><span style="color:#222222"> val) : brightness = val;</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> ShadeOfGray</span><span style="color:#222222">.</span><span style="color:#6200EE">black</span><span style="color:#222222">() : </span><span style="color:#D43324">this</span><span style="color:#222222">(</span><span style="color:#11796D">0</span><span style="color:#222222">);</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70"> // This won't parse or compile!</span></span> <span class="line"><span style="color:#6E6E70"> // ShadeOfGray.alsoBlack() : black();</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "usage_good.dart (this-dot-constructor)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> ShadeOfGray</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> final</span><span style="color:#0468D7"> int</span><span style="color:#222222"> brightness;</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> ShadeOfGray</span><span style="color:#222222">(</span><span style="color:#0468D7">int</span><span style="color:#222222"> val) : brightness = val;</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> ShadeOfGray</span><span style="color:#222222">.</span><span style="color:#6200EE">black</span><span style="color:#222222">() : </span><span style="color:#D43324">this</span><span style="color:#222222">(</span><span style="color:#11796D">0</span><span style="color:#222222">);</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70"> // But now it will!</span></span> <span class="line"><span style="color:#0468D7"> ShadeOfGray</span><span style="color:#222222">.</span><span style="color:#6200EE">alsoBlack</span><span style="color:#222222">() : </span><span style="color:#D43324">this</span><span style="color:#222222">.</span><span style="color:#6200EE">black</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Note that constructor parameters never shadow fields in constructor initializer lists:</p> <?code-excerpt "usage_good.dart (param-dont-shadow-field-ctr-init)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Box</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> BaseBox</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#0468D7"> Object</span><span style="color:#222222">? value;</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> Box</span><span style="color:#222222">(</span><span style="color:#0468D7">Object</span><span style="color:#222222">? value) : value = value, </span><span style="color:#D43324">super</span><span style="color:#222222">(value);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>This looks surprising, but works like you want. Fortunately, code like this is relatively rare thanks to initializing formals and super initializers.</p><div class="header-wrapper"><h3 id="do-initialize-fields-at-their-declaration-when-possible">DO initialize fields at their declaration when possible</h3><a class="heading-link" href="#do-initialize-fields-at-their-declaration-when-possible" aria-label="Link to 'DO initialize fields at their declaration when possible' section">#</a></div><p>If a field doesn't depend on any constructor parameters, it can and should be initialized at its declaration. It takes less code and avoids duplication when the class has multiple constructors.</p> <?code-excerpt "usage_bad.dart (field-init-at-decl)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> ProfileMark</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> final</span><span style="color:#0468D7"> String</span><span style="color:#222222"> name;</span></span> <span class="line"><span style="color:#D43324"> final</span><span style="color:#0468D7"> DateTime</span><span style="color:#222222"> start;</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> ProfileMark</span><span style="color:#222222">(</span><span style="color:#D43324">this</span><span style="color:#222222">.name) : start = </span><span style="color:#0468D7">DateTime</span><span style="color:#222222">.</span><span style="color:#6200EE">now</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#0468D7"> ProfileMark</span><span style="color:#222222">.</span><span style="color:#6200EE">unnamed</span><span style="color:#222222">() : name = </span><span style="color:#11796D">''</span><span style="color:#222222">, start = </span><span style="color:#0468D7">DateTime</span><span style="color:#222222">.</span><span style="color:#6200EE">now</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "usage_good.dart (field-init-at-decl)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> ProfileMark</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> final</span><span style="color:#0468D7"> String</span><span style="color:#222222"> name;</span></span> <span class="line"><span style="color:#D43324"> final</span><span style="color:#0468D7"> DateTime</span><span style="color:#222222"> start = </span><span style="color:#0468D7">DateTime</span><span style="color:#222222">.</span><span style="color:#6200EE">now</span><span style="color:#222222">();</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> ProfileMark</span><span style="color:#222222">(</span><span style="color:#D43324">this</span><span style="color:#222222">.name);</span></span> <span class="line"><span style="color:#0468D7"> ProfileMark</span><span style="color:#222222">.</span><span style="color:#6200EE">unnamed</span><span style="color:#222222">() : name = </span><span style="color:#11796D">''</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Some fields can't be initialized at their declarations because they need to reference <code>this</code>—to use other fields or call methods, for example. However, if the field is marked <code>late</code>, then the initializer <em>can</em> access <code>this</code>.</p><p>Of course, if a field depends on constructor parameters, or is initialized differently by different constructors, then this guideline does not apply.</p><div class="header-wrapper"><h2 id="constructors">Constructors</h2><a class="heading-link" href="#constructors" aria-label="Link to 'Constructors' section">#</a></div><p>The following best practices apply to declaring constructors for a class.</p><div class="header-wrapper"><h3 id="do-use-initializing-formals-when-possible">DO use initializing formals when possible</h3><a class="heading-link" href="#do-use-initializing-formals-when-possible" aria-label="Link to 'DO use initializing formals when possible' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/prefer_initializing_formals">prefer_initializing_formals</a></p><p>Many fields are initialized directly from a constructor parameter, like:</p> <?code-excerpt "usage_bad.dart (field-init-as-param)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Point</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#0468D7"> double</span><span style="color:#222222"> x, y;</span></span> <span class="line"><span style="color:#0468D7"> Point</span><span style="color:#222222">(</span><span style="color:#0468D7">double</span><span style="color:#222222"> x, </span><span style="color:#0468D7">double</span><span style="color:#222222"> y) : x = x, y = y;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>We've got to type <code>x</code> <em>four</em> times here to define a field. We can do better:</p> <?code-excerpt "usage_good.dart (field-init-as-param)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Point</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#0468D7"> double</span><span style="color:#222222"> x, y;</span></span> <span class="line"><span style="color:#0468D7"> Point</span><span style="color:#222222">(</span><span style="color:#D43324">this</span><span style="color:#222222">.x, </span><span style="color:#D43324">this</span><span style="color:#222222">.y);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>This <code>this.</code> syntax before a constructor parameter is called an "initializing formal". You can't always take advantage of it. Sometimes you want to have a named parameter whose name doesn't match the name of the field you are initializing. But when you <em>can</em> use initializing formals, you <em>should</em>.</p><div class="header-wrapper"><h3 id="dont-use-late-when-a-constructor-initializer-list-will-do">DON'T use <code>late</code> when a constructor initializer list will do</h3><a class="heading-link" href="#dont-use-late-when-a-constructor-initializer-list-will-do" aria-label="Link to 'DON'T use late when a constructor initializer list will do' section">#</a></div><p>Dart requires you to initialize non-nullable fields before they can be read. Since fields can be read inside the constructor body, this means you get an error if you don't initialize a non-nullable field before the body runs.</p><p>You can make this error go away by marking the field <code>late</code>. That turns the compile-time error into a <em>runtime</em> error if you access the field before it is initialized. That's what you need in some cases, but often the right fix is to initialize the field in the constructor initializer list:</p> <?code-excerpt "usage_good.dart (late-init-list)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Point</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#0468D7"> double</span><span style="color:#222222"> x, y;</span></span> <span class="line"><span style="color:#0468D7"> Point</span><span style="color:#222222">.</span><span style="color:#6200EE">polar</span><span style="color:#222222">(</span><span style="color:#0468D7">double</span><span style="color:#222222"> theta, </span><span style="color:#0468D7">double</span><span style="color:#222222"> radius)</span></span> <span class="line"><span style="color:#222222"> : x = </span><span style="color:#6200EE">cos</span><span style="color:#222222">(theta) * radius,</span></span> <span class="line"><span style="color:#222222"> y = </span><span style="color:#6200EE">sin</span><span style="color:#222222">(theta) * radius;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (late-init-list)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Point</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> late</span><span style="color:#0468D7"> double</span><span style="color:#222222"> x, y;</span></span> <span class="line"><span style="color:#0468D7"> Point</span><span style="color:#222222">.</span><span style="color:#6200EE">polar</span><span style="color:#222222">(</span><span style="color:#0468D7">double</span><span style="color:#222222"> theta, </span><span style="color:#0468D7">double</span><span style="color:#222222"> radius) {</span></span> <span class="line"><span style="color:#222222"> x = </span><span style="color:#6200EE">cos</span><span style="color:#222222">(theta) * radius;</span></span> <span class="line"><span style="color:#222222"> y = </span><span style="color:#6200EE">sin</span><span style="color:#222222">(theta) * radius;</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>The initializer list gives you access to constructor parameters and lets you initialize fields before they can be read. So, if it's possible to use an initializer list, that's better than making the field <code>late</code> and losing some static safety and performance.</p><div class="header-wrapper"><h3 id="do-use-instead-of-for-empty-constructor-bodies">DO use <code>;</code> instead of <code>{}</code> for empty constructor bodies</h3><a class="heading-link" href="#do-use-instead-of-for-empty-constructor-bodies" aria-label="Link to 'DO use ; instead of {} for empty constructor bodies' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/empty_constructor_bodies">empty_constructor_bodies</a></p><p>In Dart, a constructor with an empty body can be terminated with just a semicolon. (In fact, it's required for const constructors.)</p> <?code-excerpt "usage_good.dart (semicolon-for-empty-body)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Point</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#0468D7"> double</span><span style="color:#222222"> x, y;</span></span> <span class="line"><span style="color:#0468D7"> Point</span><span style="color:#222222">(</span><span style="color:#D43324">this</span><span style="color:#222222">.x, </span><span style="color:#D43324">this</span><span style="color:#222222">.y);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (semicolon-for-empty-body)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Point</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#0468D7"> double</span><span style="color:#222222"> x, y;</span></span> <span class="line"><span style="color:#0468D7"> Point</span><span style="color:#222222">(</span><span style="color:#D43324">this</span><span style="color:#222222">.x, </span><span style="color:#D43324">this</span><span style="color:#222222">.y) {}</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="dont-use-new">DON'T use <code>new</code></h3><a class="heading-link" href="#dont-use-new" aria-label="Link to 'DON'T use new' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/unnecessary_new">unnecessary_new</a></p><p>The <code>new</code> keyword is optional when calling a constructor. Its meaning is not clear because factory constructors mean a <code>new</code> invocation may not actually return a new object.</p><p>The language still permits <code>new</code>, but consider it deprecated and avoid using it in your code.</p> <?code-excerpt "usage_good.dart (no-new)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#0468D7"> Row</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> children: [</span><span style="color:#0468D7">RaisedButton</span><span style="color:#222222">(child: </span><span style="color:#0468D7">Text</span><span style="color:#222222">(</span><span style="color:#11796D">'Increment'</span><span style="color:#222222">)), </span><span style="color:#0468D7">Text</span><span style="color:#222222">(</span><span style="color:#11796D">'Click!'</span><span style="color:#222222">)],</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (no-new)" replace="/new/[!$&!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Widget</span><span style="color:#6200EE"> build</span><span style="color:#222222">(</span><span style="color:#0468D7">BuildContext</span><span style="color:#222222"> context) {</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#D43324"> </span><mark class="highlight"><span style="color:#D43324">new</span></mark><span style="color:#0468D7"> Row</span><span style="color:#222222">(</span></span> <span class="line"><span style="color:#222222"> children: [</span></span> <span class="line"><span style="color:#D43324"> </span><mark class="highlight"><span style="color:#D43324">new</span></mark><span style="color:#0468D7"> RaisedButton</span><span style="color:#222222">(child: </span><mark class="highlight"><span style="color:#D43324">new</span></mark><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#11796D">'Increment'</span><span style="color:#222222">)),</span></span> <span class="line"><span style="color:#D43324"> </span><mark class="highlight"><span style="color:#D43324">new</span></mark><span style="color:#0468D7"> Text</span><span style="color:#222222">(</span><span style="color:#11796D">'Click!'</span><span style="color:#222222">),</span></span> <span class="line"><span style="color:#222222"> ],</span></span> <span class="line"><span style="color:#222222"> );</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="dont-use-const-redundantly">DON'T use <code>const</code> redundantly</h3><a class="heading-link" href="#dont-use-const-redundantly" aria-label="Link to 'DON'T use const redundantly' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/unnecessary_const">unnecessary_const</a></p><p>In contexts where an expression <em>must</em> be constant, the <code>const</code> keyword is implicit, doesn't need to be written, and shouldn't. Those contexts are any expression inside:</p><ul><li>A const collection literal.</li><li>A const constructor call</li><li>A metadata annotation.</li><li>The initializer for a const variable declaration.</li><li>A switch case expression—the part right after <code>case</code> before the <code>:</code>, not the body of the case.</li></ul><p>(Default values are not included in this list because future versions of Dart may support non-const default values.)</p><p>Basically, any place where it would be an error to write <code>new</code> instead of <code>const</code>, Dart allows you to omit the <code>const</code>.</p> <?code-excerpt "usage_good.dart (no-const)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">const</span><span style="color:#222222"> primaryColors = [</span></span> <span class="line"><span style="color:#0468D7"> Color</span><span style="color:#222222">(</span><span style="color:#11796D">'red'</span><span style="color:#222222">, [</span><span style="color:#11796D">255</span><span style="color:#222222">, </span><span style="color:#11796D">0</span><span style="color:#222222">, </span><span style="color:#11796D">0</span><span style="color:#222222">]),</span></span> <span class="line"><span style="color:#0468D7"> Color</span><span style="color:#222222">(</span><span style="color:#11796D">'green'</span><span style="color:#222222">, [</span><span style="color:#11796D">0</span><span style="color:#222222">, </span><span style="color:#11796D">255</span><span style="color:#222222">, </span><span style="color:#11796D">0</span><span style="color:#222222">]),</span></span> <span class="line"><span style="color:#0468D7"> Color</span><span style="color:#222222">(</span><span style="color:#11796D">'blue'</span><span style="color:#222222">, [</span><span style="color:#11796D">0</span><span style="color:#222222">, </span><span style="color:#11796D">0</span><span style="color:#222222">, </span><span style="color:#11796D">255</span><span style="color:#222222">]),</span></span> <span class="line"><span style="color:#222222">];</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (no-const)" replace="/ (const)/ [!$1!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">const</span><span style="color:#222222"> primaryColors = </span><mark class="highlight"><span style="color:#D43324">const</span></mark><span style="color:#222222"> [</span></span> <span class="line"><span style="color:#D43324"> </span><mark class="highlight"><span style="color:#D43324">const</span></mark><span style="color:#0468D7"> Color</span><span style="color:#222222">(</span><span style="color:#11796D">'red'</span><span style="color:#222222">, </span><mark class="highlight"><span style="color:#D43324">const</span></mark><span style="color:#222222"> [</span><span style="color:#11796D">255</span><span style="color:#222222">, </span><span style="color:#11796D">0</span><span style="color:#222222">, </span><span style="color:#11796D">0</span><span style="color:#222222">]),</span></span> <span class="line"><span style="color:#D43324"> </span><mark class="highlight"><span style="color:#D43324">const</span></mark><span style="color:#0468D7"> Color</span><span style="color:#222222">(</span><span style="color:#11796D">'green'</span><span style="color:#222222">, </span><mark class="highlight"><span style="color:#D43324">const</span></mark><span style="color:#222222"> [</span><span style="color:#11796D">0</span><span style="color:#222222">, </span><span style="color:#11796D">255</span><span style="color:#222222">, </span><span style="color:#11796D">0</span><span style="color:#222222">]),</span></span> <span class="line"><span style="color:#D43324"> </span><mark class="highlight"><span style="color:#D43324">const</span></mark><span style="color:#0468D7"> Color</span><span style="color:#222222">(</span><span style="color:#11796D">'blue'</span><span style="color:#222222">, </span><mark class="highlight"><span style="color:#D43324">const</span></mark><span style="color:#222222"> [</span><span style="color:#11796D">0</span><span style="color:#222222">, </span><span style="color:#11796D">0</span><span style="color:#222222">, </span><span style="color:#11796D">255</span><span style="color:#222222">]),</span></span> <span class="line"><span style="color:#222222">];</span></span></code></pre></div></div><div class="header-wrapper"><h2 id="error-handling">Error handling</h2><a class="heading-link" href="#error-handling" aria-label="Link to 'Error handling' section">#</a></div><p>Dart uses exceptions when an error occurs in your program. The following best practices apply to catching and throwing exceptions.</p><div class="header-wrapper"><h3 id="avoid-catches-without-on-clauses">AVOID catches without <code>on</code> clauses</h3><a class="heading-link" href="#avoid-catches-without-on-clauses" aria-label="Link to 'AVOID catches without on clauses' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/avoid_catches_without_on_clauses">avoid_catches_without_on_clauses</a></p><p>A catch clause with no <code>on</code> qualifier catches <em>anything</em> thrown by the code in the try block. <a href="https://blog.codinghorror.com/new-programming-jargon/">Pokémon exception handling</a> is very likely not what you want. Does your code correctly handle <a href="https://api.dart.dev/dart-core/StackOverflowError-class.html">StackOverflowError</a> or <a href="https://api.dart.dev/dart-core/OutOfMemoryError-class.html">OutOfMemoryError</a>? If you incorrectly pass the wrong argument to a method in that try block do you want to have your debugger point you to the mistake or would you rather that helpful <a href="https://api.dart.dev/dart-core/ArgumentError-class.html">ArgumentError</a> get swallowed? Do you want any <code>assert()</code> statements inside that code to effectively vanish since you're catching the thrown <a href="https://api.dart.dev/dart-core/AssertionError-class.html">AssertionError</a>s?</p><p>The answer is probably "no", in which case you should filter the types you catch. In most cases, you should have an <code>on</code> clause that limits you to the kinds of runtime failures you are aware of and are correctly handling.</p><p>In rare cases, you may wish to catch any runtime error. This is usually in framework or low-level code that tries to insulate arbitrary application code from causing problems. Even here, it is usually better to catch <a href="https://api.dart.dev/dart-core/Exception-class.html">Exception</a> than to catch all types. Exception is the base class for all <em>runtime</em> errors and excludes errors that indicate <em>programmatic</em> bugs in the code.</p><div class="header-wrapper"><h3 id="dont-discard-errors-from-catches-without-on-clauses">DON'T discard errors from catches without <code>on</code> clauses</h3><a class="heading-link" href="#dont-discard-errors-from-catches-without-on-clauses" aria-label="Link to 'DON'T discard errors from catches without on clauses' section">#</a></div><p>If you really do feel you need to catch <em>everything</em> that can be thrown from a region of code, <em>do something</em> with what you catch. Log it, display it to the user or rethrow it, but do not silently discard it.</p><div class="header-wrapper"><h3 id="do-throw-objects-that-implement-error-only-for-programmatic-errors">DO throw objects that implement <code>Error</code> only for programmatic errors</h3><a class="heading-link" href="#do-throw-objects-that-implement-error-only-for-programmatic-errors" aria-label="Link to 'DO throw objects that implement Error only for programmatic errors' section">#</a></div><p>The <a href="https://api.dart.dev/dart-core/Error-class.html">Error</a> class is the base class for <em>programmatic</em> errors. When an object of that type or one of its subinterfaces like <a href="https://api.dart.dev/dart-core/ArgumentError-class.html">ArgumentError</a> is thrown, it means there is a <em>bug</em> in your code. When your API wants to report to a caller that it is being used incorrectly throwing an Error sends that signal clearly.</p><p>Conversely, if the exception is some kind of runtime failure that doesn't indicate a bug in the code, then throwing an Error is misleading. Instead, throw one of the core Exception classes or some other type.</p><div class="header-wrapper"><h3 id="dont-explicitly-catch-error-or-types-that-implement-it">DON'T explicitly catch <code>Error</code> or types that implement it</h3><a class="heading-link" href="#dont-explicitly-catch-error-or-types-that-implement-it" aria-label="Link to 'DON'T explicitly catch Error or types that implement it' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/avoid_catching_errors">avoid_catching_errors</a></p><p>This follows from the above. Since an Error indicates a bug in your code, it should unwind the entire callstack, halt the program, and print a stack trace so you can locate and fix the bug.</p><p>Catching errors of these types breaks that process and masks the bug. Instead of <em>adding</em> error-handling code to deal with this exception after the fact, go back and fix the code that is causing it to be thrown in the first place.</p><div class="header-wrapper"><h3 id="do-use-rethrow-to-rethrow-a-caught-exception">DO use <code>rethrow</code> to rethrow a caught exception</h3><a class="heading-link" href="#do-use-rethrow-to-rethrow-a-caught-exception" aria-label="Link to 'DO use rethrow to rethrow a caught exception' section">#</a></div><p class="linter-rule">Linter rule: <a href="/tools/linter-rules/use_rethrow_when_possible">use_rethrow_when_possible</a></p><p>If you decide to rethrow an exception, prefer using the <code>rethrow</code> statement instead of throwing the same exception object using <code>throw</code>. <code>rethrow</code> preserves the original stack trace of the exception. <code>throw</code> on the other hand resets the stack trace to the last thrown position.</p> <?code-excerpt "usage_bad.dart (rethrow)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">try</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#6200EE"> somethingRisky</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">} </span><span style="color:#D43324">catch</span><span style="color:#222222"> (e) {</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (!</span><span style="color:#6200EE">canHandle</span><span style="color:#222222">(e)) </span><span style="color:#D43324">throw</span><span style="color:#222222"> e;</span></span> <span class="line"><span style="color:#6200EE"> handle</span><span style="color:#222222">(e);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "usage_good.dart (rethrow)" replace="/rethrow/[!$&!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">try</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#6200EE"> somethingRisky</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">} </span><span style="color:#D43324">catch</span><span style="color:#222222"> (e) {</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (!</span><span style="color:#6200EE">canHandle</span><span style="color:#222222">(e)) </span><mark class="highlight"><span style="color:#D43324">rethrow</span></mark><span style="color:#222222">;</span></span> <span class="line"><span style="color:#6200EE"> handle</span><span style="color:#222222">(e);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h2 id="asynchrony">Asynchrony</h2><a class="heading-link" href="#asynchrony" aria-label="Link to 'Asynchrony' section">#</a></div><p>Dart has several language features to support asynchronous programming. The following best practices apply to asynchronous coding.</p><div class="header-wrapper"><h3 id="prefer-asyncawait-over-using-raw-futures">PREFER async/await over using raw futures</h3><a class="heading-link" href="#prefer-asyncawait-over-using-raw-futures" aria-label="Link to 'PREFER async/await over using raw futures' section">#</a></div><p>Asynchronous code is notoriously hard to read and debug, even when using a nice abstraction like futures. The <code>async</code>/<code>await</code> syntax improves readability and lets you use all of the Dart control flow structures within your async code.</p> <?code-excerpt "usage_good.dart (async-await)" replace="/async|await/[!$&!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#0468D7">int</span><span style="color:#222222">> </span><span style="color:#6200EE">countActivePlayers</span><span style="color:#222222">(</span><span style="color:#0468D7">String</span><span style="color:#222222"> teamName) </span><mark class="highlight"><span style="color:#D43324">async</span></mark><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> try</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> var</span><span style="color:#222222"> team = </span><mark class="highlight"><span style="color:#D43324">await</span></mark><span style="color:#6200EE"> downloadTeam</span><span style="color:#222222">(teamName);</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (team == </span><span style="color:#11796D">null</span><span style="color:#222222">) </span><span style="color:#D43324">return</span><span style="color:#11796D"> 0</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> var</span><span style="color:#222222"> players = </span><mark class="highlight"><span style="color:#D43324">await</span></mark><span style="color:#222222"> team.roster;</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> players.</span><span style="color:#6200EE">where</span><span style="color:#222222">((player) => player.isActive).length;</span></span> <span class="line"><span style="color:#222222"> } </span><span style="color:#D43324">catch</span><span style="color:#222222"> (e) {</span></span> <span class="line"><span style="color:#222222"> log.</span><span style="color:#6200EE">error</span><span style="color:#222222">(e);</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#11796D"> 0</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (async-await)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#0468D7">int</span><span style="color:#222222">> </span><span style="color:#6200EE">countActivePlayers</span><span style="color:#222222">(</span><span style="color:#0468D7">String</span><span style="color:#222222"> teamName) {</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#6200EE"> downloadTeam</span><span style="color:#222222">(teamName)</span></span> <span class="line"><span style="color:#222222"> .</span><span style="color:#6200EE">then</span><span style="color:#222222">((team) {</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (team == </span><span style="color:#11796D">null</span><span style="color:#222222">) </span><span style="color:#D43324">return</span><span style="color:#0468D7"> Future</span><span style="color:#222222">.</span><span style="color:#6200EE">value</span><span style="color:#222222">(</span><span style="color:#11796D">0</span><span style="color:#222222">);</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> team.roster.</span><span style="color:#6200EE">then</span><span style="color:#222222">((players) {</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> players.</span><span style="color:#6200EE">where</span><span style="color:#222222">((player) => player.isActive).length;</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"><span style="color:#222222"> })</span></span> <span class="line"><span style="color:#222222"> .</span><span style="color:#6200EE">catchError</span><span style="color:#222222">((e) {</span></span> <span class="line"><span style="color:#222222"> log.</span><span style="color:#6200EE">error</span><span style="color:#222222">(e);</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#11796D"> 0</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="dont-use-async-when-it-has-no-useful-effect">DON'T use <code>async</code> when it has no useful effect</h3><a class="heading-link" href="#dont-use-async-when-it-has-no-useful-effect" aria-label="Link to 'DON'T use async when it has no useful effect' section">#</a></div><p>It's easy to get in the habit of using <code>async</code> on any function that does anything related to asynchrony. But in some cases, it's extraneous. If you can omit the <code>async</code> without changing the behavior of the function, do so.</p> <?code-excerpt "usage_good.dart (unnecessary-async)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#0468D7">int</span><span style="color:#222222">> </span><span style="color:#6200EE">fastestBranch</span><span style="color:#222222">(</span><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#0468D7">int</span><span style="color:#222222">> left, </span><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#0468D7">int</span><span style="color:#222222">> right) {</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#0468D7"> Future</span><span style="color:#222222">.</span><span style="color:#6200EE">any</span><span style="color:#222222">([left, right]);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (unnecessary-async)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#0468D7">int</span><span style="color:#222222">> </span><span style="color:#6200EE">fastestBranch</span><span style="color:#222222">(</span><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#0468D7">int</span><span style="color:#222222">> left, </span><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#0468D7">int</span><span style="color:#222222">> right) </span><span style="color:#D43324">async</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#0468D7"> Future</span><span style="color:#222222">.</span><span style="color:#6200EE">any</span><span style="color:#222222">([left, right]);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Cases where <code>async</code> <em>is</em> useful include:</p><ul><li><p>You are using <code>await</code>. (This is the obvious one.)</p></li><li><p>You are returning an error asynchronously. <code>async</code> and then <code>throw</code> is shorter than <code>return Future.error(...)</code>.</p></li><li><p>You are returning a value and you want it implicitly wrapped in a future. <code>async</code> is shorter than <code>Future.value(...)</code>.</p></li></ul> <?code-excerpt "usage_good.dart (async)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#D43324">void</span><span style="color:#222222">> </span><span style="color:#6200EE">usesAwait</span><span style="color:#222222">(</span><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#0468D7">String</span><span style="color:#222222">> later) </span><span style="color:#D43324">async</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#6200EE"> print</span><span style="color:#222222">(</span><span style="color:#D43324">await</span><span style="color:#222222"> later);</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#D43324">void</span><span style="color:#222222">> </span><span style="color:#6200EE">asyncError</span><span style="color:#222222">() </span><span style="color:#D43324">async</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> throw</span><span style="color:#11796D"> 'Error!'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#0468D7">String</span><span style="color:#222222">> </span><span style="color:#6200EE">asyncValue</span><span style="color:#222222">() </span><span style="color:#D43324">async</span><span style="color:#222222"> => </span><span style="color:#11796D">'value'</span><span style="color:#222222">;</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="consider-using-higher-order-methods-to-transform-a-stream">CONSIDER using higher-order methods to transform a stream</h3><a class="heading-link" href="#consider-using-higher-order-methods-to-transform-a-stream" aria-label="Link to 'CONSIDER using higher-order methods to transform a stream' section">#</a></div><p>This parallels the above suggestion on iterables. Streams support many of the same methods and also handle things like transmitting errors, closing, etc. correctly.</p><div class="header-wrapper"><h3 id="avoid-using-completer-directly">AVOID using Completer directly</h3><a class="heading-link" href="#avoid-using-completer-directly" aria-label="Link to 'AVOID using Completer directly' section">#</a></div><p>Many people new to asynchronous programming want to write code that produces a future. The constructors in Future don't seem to fit their need so they eventually find the Completer class and use that.</p> <?code-excerpt "usage_bad.dart (avoid-completer)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#0468D7">bool</span><span style="color:#222222">> </span><span style="color:#6200EE">fileContainsBear</span><span style="color:#222222">(</span><span style="color:#0468D7">String</span><span style="color:#222222"> path) {</span></span> <span class="line"><span style="color:#D43324"> var</span><span style="color:#222222"> completer = </span><span style="color:#0468D7">Completer</span><span style="color:#222222"><</span><span style="color:#0468D7">bool</span><span style="color:#222222">>();</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> File</span><span style="color:#222222">(path).</span><span style="color:#6200EE">readAsString</span><span style="color:#222222">().</span><span style="color:#6200EE">then</span><span style="color:#222222">((contents) {</span></span> <span class="line"><span style="color:#222222"> completer.</span><span style="color:#6200EE">complete</span><span style="color:#222222">(contents.</span><span style="color:#6200EE">contains</span><span style="color:#222222">(</span><span style="color:#11796D">'bear'</span><span style="color:#222222">));</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> completer.future;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Completer is needed for two kinds of low-level code: new asynchronous primitives, and interfacing with asynchronous code that doesn't use futures. Most other code should use async/await or <a href="https://api.dart.dev/dart-async/Future/then.html"><code>Future.then()</code></a>, because they're clearer and make error handling easier.</p> <?code-excerpt "usage_good.dart (avoid-completer)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#0468D7">bool</span><span style="color:#222222">> </span><span style="color:#6200EE">fileContainsBear</span><span style="color:#222222">(</span><span style="color:#0468D7">String</span><span style="color:#222222"> path) {</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#0468D7"> File</span><span style="color:#222222">(path).</span><span style="color:#6200EE">readAsString</span><span style="color:#222222">().</span><span style="color:#6200EE">then</span><span style="color:#222222">((contents) {</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> contents.</span><span style="color:#6200EE">contains</span><span style="color:#222222">(</span><span style="color:#11796D">'bear'</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#222222"> });</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "usage_good.dart (avoid-completer-alt)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#0468D7">bool</span><span style="color:#222222">> </span><span style="color:#6200EE">fileContainsBear</span><span style="color:#222222">(</span><span style="color:#0468D7">String</span><span style="color:#222222"> path) </span><span style="color:#D43324">async</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> var</span><span style="color:#222222"> contents = </span><span style="color:#D43324">await</span><span style="color:#0468D7"> File</span><span style="color:#222222">(path).</span><span style="color:#6200EE">readAsString</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> contents.</span><span style="color:#6200EE">contains</span><span style="color:#222222">(</span><span style="color:#11796D">'bear'</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="do-test-for-futuret-when-disambiguating-a-futureort-whose-type-argument-could-be-object">DO test for <code>Future<T></code> when disambiguating a <code>FutureOr<T></code> whose type argument could be <code>Object</code></h3><a class="heading-link" href="#do-test-for-futuret-when-disambiguating-a-futureort-whose-type-argument-could-be-object" aria-label="Link to 'DO test for Future<T> when disambiguating a FutureOr<T> whose type argument could be Object' section">#</a></div><p>Before you can do anything useful with a <code>FutureOr<T></code>, you typically need to do an <code>is</code> check to see if you have a <code>Future<T></code> or a bare <code>T</code>. If the type argument is some specific type as in <code>FutureOr<int></code>, it doesn't matter which test you use, <code>is int</code> or <code>is Future<int></code>. Either works because those two types are disjoint.</p><p>However, if the value type is <code>Object</code> or a type parameter that could possibly be instantiated with <code>Object</code>, then the two branches overlap. <code>Future<Object></code> itself implements <code>Object</code>, so <code>is Object</code> or <code>is T</code> where <code>T</code> is some type parameter that could be instantiated with <code>Object</code> returns true even when the object is a future. Instead, explicitly test for the <code>Future</code> case:</p> <?code-excerpt "usage_good.dart (test-future-or)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-good"><span class="code-block-tag">good</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#0468D7">T</span><span style="color:#222222">> </span><span style="color:#6200EE">logValue</span><span style="color:#222222"><</span><span style="color:#0468D7">T</span><span style="color:#222222">>(</span><span style="color:#0468D7">FutureOr</span><span style="color:#222222"><</span><span style="color:#0468D7">T</span><span style="color:#222222">> value) </span><span style="color:#D43324">async</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (value is </span><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#0468D7">T</span><span style="color:#222222">>) {</span></span> <span class="line"><span style="color:#D43324"> var</span><span style="color:#222222"> result = </span><span style="color:#D43324">await</span><span style="color:#222222"> value;</span></span> <span class="line"><span style="color:#6200EE"> print</span><span style="color:#222222">(result);</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> result;</span></span> <span class="line"><span style="color:#222222"> } </span><span style="color:#D43324">else</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#6200EE"> print</span><span style="color:#222222">(value);</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> value;</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "usage_bad.dart (test-future-or)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-bad"><span class="code-block-tag">bad</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Future</span><span style="color:#222222"><</span><span style="color:#0468D7">T</span><span style="color:#222222">> </span><span style="color:#6200EE">logValue</span><span style="color:#222222"><</span><span style="color:#0468D7">T</span><span style="color:#222222">>(</span><span style="color:#0468D7">FutureOr</span><span style="color:#222222"><</span><span style="color:#0468D7">T</span><span style="color:#222222">> value) </span><span style="color:#D43324">async</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (value is </span><span style="color:#0468D7">T</span><span style="color:#222222">) {</span></span> <span class="line"><span style="color:#6200EE"> print</span><span style="color:#222222">(value);</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> value;</span></span> <span class="line"><span style="color:#222222"> } </span><span style="color:#D43324">else</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> var</span><span style="color:#222222"> result = </span><span style="color:#D43324">await</span><span style="color:#222222"> value;</span></span> <span class="line"><span style="color:#6200EE"> print</span><span style="color:#222222">(result);</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> result;</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>In the bad example, if you pass it a <code>Future<Object></code>, it incorrectly treats it like a bare, synchronous value.</p><nav id="prev-next"><ul><li class="previous"><a href="/effective-dart/documentation">⟨ Documentation</a></li><li class="next"><a href="/effective-dart/design">Design ⟩</a></li></ul></nav><p id="page-github-links"><span>Unless stated otherwise, the documentation on this site reflects Dart 3.7.2. Page last updated on 2025-02-12.</span> <a href="https://github.com/dart-lang/site-www/tree/main/src/content/effective-dart/usage.md" target="_blank" rel="noopener">View source</a> <span>or </span><a href="https://github.com/dart-lang/site-www/issues/new?template=1_page_issue.yml&page-url=https://dart.dev/effective-dart/usage/&page-source=https://github.com/dart-lang/site-www/tree/main/src/content/effective-dart/usage.md" title="Report an issue with this page" target="_blank" rel="noopener">report an issue</a>.</p></div></article></main></div><footer id="page-footer"><div class="footer-section footer-main"><a href="/" class="brand" title="Dart"><img src="/assets/img/logo/logo-white-text.svg" alt="Dart" width="164"></a><div class="footer-social-links"><a href="https://medium.com/dartlang" target="_blank" rel="noopener" title="Dart's Medium publication"><svg><use href="/assets/img/social/medium.svg#medium"></use></svg> </a><a href="https://github.com/dart-lang" target="_blank" rel="noopener" title="Dart's GitHub organization"><svg><use href="/assets/img/social/github.svg#github"></use></svg> </a><a href="https://bsky.app/profile/dart.dev" target="_blank" rel="noopener" title="Dart's Bluesky profile"><svg><use href="/assets/img/social/bluesky.svg#bluesky"></use></svg> </a><a href="https://twitter.com/dart_lang" target="_blank" rel="noopener" title="Dart's X (Twitter) profile"><svg><use href="/assets/img/social/x.svg#x"></use></svg></a></div></div><div class="footer-section footer-tray"><div class="footer-licenses">Except as otherwise noted, this site is licensed under a <a href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>, and code samples are licensed under the <a href="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</a>.</div><div class="footer-utility-links"><ul><li><a href="/terms" title="Terms of use">Terms</a></li><li><a href="https://policies.google.com/privacy" target="_blank" rel="noopener" title="Privacy policy">Privacy</a></li><li><a href="/security" title="Security philosophy and practices">Security</a></li></ul></div></div></footer></div></body></html>