CINXE.COM

Understanding null safety | 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="A deep dive into Dart language and library changes related to null safety."><title>Understanding null safety | 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="Understanding null safety"><meta name="twitter:description" content="A deep dive into Dart language and library changes related to null safety."><meta property="og:title" content="Understanding null safety"><meta property="og:description" content="A deep dive into Dart language and library changes related to null safety."><meta property="og:url" content="/null-safety/understanding-null-safety/"><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,0" rel="stylesheet"><link rel="stylesheet" href="/assets/css/main.css"><script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.0/jquery.min.js" integrity="sha512-3gJwYpMe3QewGELv8k/BX9vcqhryRdzRMxVfq6ngyWXwo03GFEzjsUm8Q7RZcHPHksttq7/GFoxjCVUjkjvPdw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.2/js/bootstrap.min.js" integrity="sha384-+sLIOodYLS7CIrQpBjl+C7nPvqq+FbNUBDunl/OZv93DB7Ln/533i8e/mZXLi/P+" crossorigin="anonymous" referrerpolicy="no-referrer"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/js-cookie/3.0.5/js.cookie.min.js" integrity="sha512-nlp9/l96/EpjYBx7EP7pGASVXNe80hGhYAUrjeXnu/fyF5Py0/RXav4BBNs7n5Hx1WFhOEOWSAVjGeC3oKxDVQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script><script src="/assets/js/os-tabs.js"></script><script src="/assets/js/utilities.js"></script><script src="/assets/js/main.js"></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 show_banner"><a id="skip" href="#site-content-title">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. <a href="https://policies.google.com/technologies/cookies" target="_blank" rel="noopener">Learn more</a>.</p><button id="cookie-consent" class="btn btn-primary">OK, got it</button></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><header id="page-header" class="site-header"><nav id="mainnav" class="site-header"><div id="menu-toggle"><i class="material-symbols">menu</i></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="/guides" class="nav-link"><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 class="banner"><p class="banner__text">Announcing Dart 3.5 and an updated Dart roadmap! <a href="https://medium.com/dartlang/dart-3-5-6ca36259fa2f" target="_blank">Learn more</a></p></div><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><div class="site-sidebar"><ul class="navbar-nav"><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="/guides" class="nav-link">Docs</a></li><li aria-hidden="true"><div class="sidebar-primary-divider"></div></li></ul><ul class="nav flex-column"><li class="nav-item"><a class="nav-link active collapsible" data-toggle="collapse" href="#sidenav-1" role="button" aria-expanded="true" aria-controls="sidenav-1">Language</a><ul class="nav flex-column flex-nowrap collapse show" id="sidenav-1"><li class="nav-item"><a class="nav-link" href="/language">Introduction</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-1-2" href="#sidenav-1-2" role="button" aria-expanded="false" aria-controls="sidenav-1-2">Syntax basics</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-1-2"><li class="nav-item"><a class="nav-link" href="/language/variables">Variables</a></li><li class="nav-item"><a class="nav-link" href="/language/operators">Operators</a></li><li class="nav-item"><a class="nav-link" href="/language/comments">Comments</a></li><li class="nav-item"><a class="nav-link" href="/language/metadata">Metadata</a></li><li class="nav-item"><a class="nav-link" href="/language/libraries">Libraries & imports</a></li><li class="nav-item"><a class="nav-link" href="/language/keywords">Keywords</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-1-3" href="#sidenav-1-3" role="button" aria-expanded="false" aria-controls="sidenav-1-3">Types</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-1-3"><li class="nav-item"><a class="nav-link" href="/language/built-in-types">Built-in types</a></li><li class="nav-item"><a class="nav-link" href="/language/records">Records</a></li><li class="nav-item"><a class="nav-link" href="/language/collections">Collections</a></li><li class="nav-item"><a class="nav-link" href="/language/generics">Generics</a></li><li class="nav-item"><a class="nav-link" href="/language/typedefs">Typedefs</a></li><li class="nav-item"><a class="nav-link" href="/language/type-system">Type system</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-1-4" href="#sidenav-1-4" role="button" aria-expanded="false" aria-controls="sidenav-1-4">Patterns</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-1-4"><li class="nav-item"><a class="nav-link" href="/language/patterns">Overview & usage</a></li><li class="nav-item"><a class="nav-link" href="/language/pattern-types">Pattern types</a></li><li class="nav-item"><a class="nav-link" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records" target="_blank" rel="noopener">Applied tutorial</a></li></ul></li><li class="nav-item"><a class="nav-link" href="/language/functions">Functions</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-1-6" href="#sidenav-1-6" role="button" aria-expanded="false" aria-controls="sidenav-1-6">Control flow</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-1-6"><li class="nav-item"><a class="nav-link" href="/language/loops">Loops</a></li><li class="nav-item"><a class="nav-link" href="/language/branches">Branches</a></li><li class="nav-item"><a class="nav-link" href="/language/error-handling">Error handling</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-1-7" href="#sidenav-1-7" role="button" aria-expanded="false" aria-controls="sidenav-1-7">Classes & objects</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-1-7"><li class="nav-item"><a class="nav-link" href="/language/classes">Classes</a></li><li class="nav-item"><a class="nav-link" href="/language/constructors">Constructors</a></li><li class="nav-item"><a class="nav-link" href="/language/methods">Methods</a></li><li class="nav-item"><a class="nav-link" href="/language/extend">Extend a class</a></li><li class="nav-item"><a class="nav-link" href="/language/mixins">Mixins</a></li><li class="nav-item"><a class="nav-link" href="/language/enums">Enums</a></li><li class="nav-item"><a class="nav-link" href="/language/extension-methods">Extension methods</a></li><li class="nav-item"><a class="nav-link" href="/language/extension-types">Extension types</a></li><li class="nav-item"><a class="nav-link" href="/language/callable-objects">Callable objects</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-1-8" href="#sidenav-1-8" role="button" aria-expanded="false" aria-controls="sidenav-1-8">Class modifiers</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-1-8"><li class="nav-item"><a class="nav-link" href="/language/class-modifiers">Overview & usage</a></li><li class="nav-item"><a class="nav-link" href="/language/class-modifiers-for-apis">Class modifiers for API maintainers</a></li><li class="nav-item"><a class="nav-link" href="/language/modifier-reference">Reference</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-1-9" href="#sidenav-1-9" role="button" aria-expanded="false" aria-controls="sidenav-1-9">Concurrency</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-1-9"><li class="nav-item"><a class="nav-link" href="/language/concurrency">Overview</a></li><li class="nav-item"><a class="nav-link" href="/language/async">Asynchronous support</a></li><li class="nav-item"><a class="nav-link" href="/language/isolates">Isolates</a></li></ul></li><li class="nav-item"><a class="nav-link active collapsible" data-toggle="collapse" data-target="#sidenav-1-10" href="#sidenav-1-10" role="button" aria-expanded="true" aria-controls="sidenav-1-10">Null safety</a><ul class="nav flex-column flex-nowrap collapse show" id="sidenav-1-10"><li class="nav-item"><a class="nav-link" href="/null-safety">Sound null safety</a></li><li class="nav-item"><a class="nav-link" href="/null-safety/migration-guide">Migrating to null safety</a></li><li class="nav-item"><a class="nav-link active" href="/null-safety/understanding-null-safety">Understanding null safety</a></li><li class="nav-item"><a class="nav-link" href="/null-safety/unsound-null-safety">Unsound null safety</a></li><li class="nav-item"><a class="nav-link" href="/null-safety/faq">FAQ</a></li></ul></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#sidenav-2" role="button" aria-expanded="false" aria-controls="sidenav-2">Core libraries</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-2"><li class="nav-item"><a class="nav-link" href="/libraries">Overview</a></li><li class="nav-item"><a class="nav-link" href="/libraries/dart-core">dart:core</a></li><li class="nav-item"><a class="nav-link" href="/libraries/dart-async">dart:async</a></li><li class="nav-item"><a class="nav-link" href="/libraries/dart-math">dart:math</a></li><li class="nav-item"><a class="nav-link" href="/libraries/dart-convert">dart:convert</a></li><li class="nav-item"><a class="nav-link" href="/libraries/dart-io">dart:io</a></li><li class="nav-item"><a class="nav-link" href="/libraries/dart-html">dart:html</a></li><div class="dropdown-divider"></div><li class="nav-item"><a class="nav-link" href="/libraries/collections/iterables">Iterable collections</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-2-10" href="#sidenav-2-10" role="button" aria-expanded="false" aria-controls="sidenav-2-10">Asynchronous programming</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-2-10"><li class="nav-item"><a class="nav-link" href="/libraries/async/async-await">Tutorial</a></li><li class="nav-item"><a class="nav-link" href="/libraries/async/futures-error-handling">Futures and error handling</a></li><li class="nav-item"><a class="nav-link" href="/libraries/async/using-streams">Using streams</a></li><li class="nav-item"><a class="nav-link" href="/libraries/async/creating-streams">Creating streams</a></li></ul></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#sidenav-3" role="button" aria-expanded="false" aria-controls="sidenav-3">Effective Dart</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-3"><li class="nav-item"><a class="nav-link" href="/effective-dart">Overview</a></li><li class="nav-item"><a class="nav-link" href="/effective-dart/style">Style</a></li><li class="nav-item"><a class="nav-link" href="/effective-dart/documentation">Documentation</a></li><li class="nav-item"><a class="nav-link" href="/effective-dart/usage">Usage</a></li><li class="nav-item"><a class="nav-link" href="/effective-dart/design">Design</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#sidenav-4" role="button" aria-expanded="false" aria-controls="sidenav-4">Packages</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-4"><li class="nav-item"><a class="nav-link" href="/tools/pub/packages">How to use packages</a></li><li class="nav-item"><a class="nav-link" href="/resources/useful-packages">Commonly used packages</a></li><li class="nav-item"><a class="nav-link" href="/guides/libraries/create-packages">Creating packages</a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/publishing">Publishing packages</a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/writing-package-pages">Writing package pages</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-4-6" href="#sidenav-4-6" role="button" aria-expanded="false" aria-controls="sidenav-4-6">Package reference</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-4-6"><li class="nav-item"><a class="nav-link" href="/tools/pub/dependencies">Dependencies</a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/glossary">Glossary</a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/package-layout">Package layout conventions</a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/environment-variables">Pub environment variables</a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/pubspec">Pubspec file</a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/troubleshoot">Troubleshooting pub</a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/verified-publishers">Verified publishers</a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/security-advisories">Security advisories</a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/versioning">Versioning</a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/custom-package-repositories">Custom package repositories</a></li></ul></li><li class="nav-item"><a class="nav-link" href="/guides/libraries/private-files">What not to commit</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#sidenav-5" role="button" aria-expanded="false" aria-controls="sidenav-5">Development</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-5"><li class="nav-item"><a class="nav-link" href="/guides/json">JSON</a></li><li class="nav-item"><a class="nav-link" href="/guides/language/numbers">Number representation</a></li><li class="nav-item"><a class="nav-link" href="/resources/google-apis">Google APIs</a></li><li class="nav-item"><a class="nav-link" href="/multiplatform-apps">Multi-platform apps</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-5-5" href="#sidenav-5-5" role="button" aria-expanded="false" aria-controls="sidenav-5-5">Command-line & server apps</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-5-5"><li class="nav-item"><a class="nav-link" href="/server">Overview</a></li><li class="nav-item"><a class="nav-link" href="/tutorials/server/get-started">Get started</a></li><li class="nav-item"><a class="nav-link" href="/tutorials/server/cmdline">Write command-line apps</a></li><li class="nav-item"><a class="nav-link" href="/tutorials/server/fetch-data">Fetch data from the internet</a></li><li class="nav-item"><a class="nav-link" href="/tutorials/server/httpserver">Write HTTP servers</a></li><li class="nav-item"><a class="nav-link" href="/server/libraries">Libraries & packages</a></li><li class="nav-item"><a class="nav-link" href="/server/google-cloud">Google Cloud</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-5-6" href="#sidenav-5-6" role="button" aria-expanded="false" aria-controls="sidenav-5-6">Web apps</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-5-6"><li class="nav-item"><a class="nav-link" href="/web">Overview</a></li><li class="nav-item"><a class="nav-link" href="/web/get-started">Get started</a></li><li class="nav-item"><a class="nav-link" href="/web/deployment">Deployment</a></li><li class="nav-item"><a class="nav-link" href="/web/libraries">Libraries & packages</a></li><li class="nav-item"><a class="nav-link" href="/web/wasm">Wasm compilation</a></li></ul></li><li class="nav-item"><a class="nav-link" href="/guides/environment-declarations">Environment declarations</a></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#sidenav-6" role="button" aria-expanded="false" aria-controls="sidenav-6">Interoperability</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-6"><li class="nav-item"><a class="nav-link" href="/interop/c-interop">C interop</a></li><li class="nav-item"><a class="nav-link" href="/interop/objective-c-interop">Objective-C & Swift interop</a></li><li class="nav-item"><a class="nav-link" href="/interop/java-interop">Java & Kotlin interop</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-6-4" href="#sidenav-6-4" role="button" aria-expanded="false" aria-controls="sidenav-6-4">JavaScript interop</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-6-4"><li class="nav-item"><a class="nav-link" href="/interop/js-interop">Overview</a></li><li class="nav-item"><a class="nav-link" href="/interop/js-interop/usage">Usage</a></li><li class="nav-item"><a class="nav-link" href="/interop/js-interop/js-types">JS types</a></li><li class="nav-item"><a class="nav-link" href="/interop/js-interop/tutorials">Tutorials</a></li><li class="nav-item"><a class="nav-link" href="/interop/js-interop/past-js-interop">Past JS interop</a></li><div class="dropdown-divider"></div><li class="nav-item"><a class="nav-link" href="/interop/js-interop/package-web">Web interop</a></li></ul></li></ul></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#sidenav-7" role="button" aria-expanded="false" aria-controls="sidenav-7">Tools & techniques</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-7"><li class="nav-item"><a class="nav-link" href="/tools">Overview</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-7-2" href="#sidenav-7-2" role="button" aria-expanded="false" aria-controls="sidenav-7-2">Editors & debuggers</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-7-2"><li class="nav-item"><a class="nav-link" href="/tools/jetbrains-plugin">IntelliJ & Android Studio</a></li><li class="nav-item"><a class="nav-link" href="/tools/vs-code">VS Code</a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-devtools">Dart DevTools</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-7-2-4" href="#sidenav-7-2-4" role="button" aria-expanded="false" aria-controls="sidenav-7-2-4">DartPad</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-7-2-4"><li class="nav-item"><a class="nav-link" href="/tools/dartpad">Overview</a></li><li class="nav-item"><a class="nav-link" href="/tools/dartpad/troubleshoot">Troubleshooting DartPad</a></li></ul></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-7-3" href="#sidenav-7-3" role="button" aria-expanded="false" aria-controls="sidenav-7-3">Command-line tools</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-7-3"><li class="nav-item"><a class="nav-link collapsible" data-toggle="collapse" data-target="#sidenav-7-3-1" href="#sidenav-7-3-1" role="button" aria-expanded="true" aria-controls="sidenav-7-3-1">Dart SDK</a><ul class="nav flex-column flex-nowrap collapse show" id="sidenav-7-3-1"><li class="nav-item"><a class="nav-link" href="/tools/sdk">Overview</a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-tool">dart</a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-analyze">dart analyze</a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-compile">dart compile</a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-create">dart create</a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-doc">dart doc</a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-fix">dart fix</a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-format">dart format</a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-info">dart info</a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/cmd">dart pub</a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-run">dart run</a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-test">dart test</a></li><li class="nav-item"><a class="nav-link" href="/tools/dartaotruntime">dartaotruntime</a></li><li class="nav-item"><a class="nav-link" href="/tools/experiment-flags">Experiment flags</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible" data-toggle="collapse" data-target="#sidenav-7-3-2" href="#sidenav-7-3-2" role="button" aria-expanded="true" aria-controls="sidenav-7-3-2">Other command-line tools</a><ul class="nav flex-column flex-nowrap collapse show" id="sidenav-7-3-2"><li class="nav-item"><a class="nav-link" href="/tools/build_runner">build_runner</a></li><li class="nav-item"><a class="nav-link" href="/tools/webdev">webdev</a></li></ul></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-7-4" href="#sidenav-7-4" role="button" aria-expanded="false" aria-controls="sidenav-7-4">Static analysis</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-7-4"><li class="nav-item"><a class="nav-link" href="/tools/analysis">Customizing static analysis</a></li><li class="nav-item"><a class="nav-link" href="/guides/language/sound-problems">Fixing common type problems</a></li><li class="nav-item"><a class="nav-link" href="/tools/non-promotion-reasons">Fixing type promotion failures</a></li><li class="nav-item"><a class="nav-link" href="/tools/linter-rules">Linter rules</a></li><li class="nav-item"><a class="nav-link" href="/tools/diagnostic-messages">Diagnostic messages</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-7-5" href="#sidenav-7-5" role="button" aria-expanded="false" aria-controls="sidenav-7-5">Testing & optimization</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-7-5"><li class="nav-item"><a class="nav-link" href="/guides/testing">Testing</a></li><li class="nav-item"><a class="nav-link" href="/web/debugging">Debugging web apps</a></li></ul></li></ul></li><li aria-hidden="true"><div class="sidebar-primary-divider"></div></li><li class="nav-item"><a class="nav-link collapsed collapsible" data-toggle="collapse" href="#sidenav-9" role="button" aria-expanded="false" aria-controls="sidenav-9">Resources</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-9"><li class="nav-item"><a class="nav-link" href="/resources/dart-cheatsheet">Language cheatsheet</a></li><li class="nav-item"><a class="nav-link" href="/resources/breaking-changes">Breaking changes</a></li><li class="nav-item"><a class="nav-link" href="/guides/language/evolution">Language evolution</a></li><li class="nav-item"><a class="nav-link" href="/guides/language/spec">Language specification</a></li><li class="nav-item"><a class="nav-link" href="/resources/dart-3-migration">Dart 3 migration guide</a></li><li class="nav-item"><a class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#sidenav-9-6" href="#sidenav-9-6" role="button" aria-expanded="false" aria-controls="sidenav-9-6">Coming from ...</a><ul class="nav flex-column flex-nowrap collapse" id="sidenav-9-6"><li class="nav-item"><a class="nav-link" href="/resources/coming-from/js-to-dart">JavaScript to Dart</a></li><li class="nav-item"><a class="nav-link" href="/resources/coming-from/swift-to-dart">Swift to Dart</a></li></ul></li><div class="dropdown-divider"></div><li class="nav-item"><a class="nav-link" href="/resources/faq">FAQ</a></li><li class="nav-item"><a class="nav-link" href="/resources/glossary">Glossary</a></li><li class="nav-item"><a class="nav-link" href="/resources/books">Books</a></li><li class="nav-item"><a class="nav-link" href="/resources/videos">Videos</a></li><li class="nav-item"><a class="nav-link" href="/tutorials">Tutorials</a></li></ul></li><li class="nav-item"><a class="nav-link collapsible" data-toggle="collapse" href="#sidenav-10" role="button" aria-expanded="true" aria-controls="sidenav-10">Related sites</a><ul class="nav flex-column flex-nowrap collapse show" id="sidenav-10"><li class="nav-item"><a class="nav-link" href="https://api.dart.dev" target="_blank" rel="noopener">API reference</a></li><li class="nav-item"><a class="nav-link" href="https://medium.com/dartlang" target="_blank" rel="noopener">Blog</a></li><li class="nav-item"><a class="nav-link" href="https://dartpad.dev" target="_blank" rel="noopener">DartPad (online editor)</a></li><li class="nav-item"><a class="nav-link" href="https://flutter.dev" target="_blank" rel="noopener">Flutter</a></li><li class="nav-item"><a class="nav-link" href="https://pub.dev" target="_blank" rel="noopener">Package site</a></li></ul></li></ul></div></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="#nullability-in-the-type-system">Nullability in the type system</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#non-nullable-and-nullable-types">Non-nullable and nullable types</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#using-nullable-types">Using nullable types</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#top-and-bottom">Top and bottom</a></li></ul></li><li class="toc-entry nav-item"><a class="nav-link" href="#ensuring-correctness">Ensuring correctness</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#invalid-returns">Invalid returns</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#uninitialized-variables">Uninitialized variables</a></li></ul></li><li class="toc-entry nav-item"><a class="nav-link" href="#flow-analysis">Flow analysis</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#reachability-analysis">Reachability analysis</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#never-for-unreachable-code">Never for unreachable code</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#definite-assignment-analysis">Definite assignment analysis</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#type-promotion-on-null-checks">Type promotion on null checks</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#unnecessary-code-warnings">Unnecessary code warnings</a></li></ul></li><li class="toc-entry nav-item"><a class="nav-link" href="#working-with-nullable-types">Working with nullable types</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#smarter-null-aware-methods">Smarter null-aware methods</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#non-null-assertion-operator">Non-null assertion operator</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#late-variables">Late variables</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#lazy-initialization">Lazy initialization</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#late-final-variables">Late final variables</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#required-named-parameters">Required named parameters</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#abstract-fields">Abstract fields</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#working-with-nullable-fields">Working with nullable fields</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#nullability-and-generics">Nullability and generics</a></li></ul></li><li class="toc-entry nav-item"><a class="nav-link" href="#core-library-changes">Core library changes</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#the-map-index-operator-is-nullable">The Map index operator is nullable</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#no-unnamed-list-constructor">No unnamed List constructor</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#cannot-set-a-larger-length-on-non-nullable-lists">Cannot set a larger length on non-nullable lists</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#cannot-access-iterator-current-before-or-after-iteration">Cannot access Iterator.current before or after iteration</a></li></ul></li><li class="toc-entry nav-item"><a class="nav-link" href="#summary">Summary</a></li></ul></div><article><div class="content"><div id="site-content-title"><h1>Understanding null safety</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="#nullability-in-the-type-system">Nullability in the type system</a><ul><li class="toc-entry"><a href="#non-nullable-and-nullable-types">Non-nullable and nullable types</a></li><li class="toc-entry"><a href="#using-nullable-types">Using nullable types</a></li><li class="toc-entry"><a href="#top-and-bottom">Top and bottom</a></li></ul></li><li class="toc-entry"><a href="#ensuring-correctness">Ensuring correctness</a><ul><li class="toc-entry"><a href="#invalid-returns">Invalid returns</a></li><li class="toc-entry"><a href="#uninitialized-variables">Uninitialized variables</a></li></ul></li><li class="toc-entry"><a href="#flow-analysis">Flow analysis</a><ul><li class="toc-entry"><a href="#reachability-analysis">Reachability analysis</a></li><li class="toc-entry"><a href="#never-for-unreachable-code">Never for unreachable code</a></li><li class="toc-entry"><a href="#definite-assignment-analysis">Definite assignment analysis</a></li><li class="toc-entry"><a href="#type-promotion-on-null-checks">Type promotion on null checks</a></li><li class="toc-entry"><a href="#unnecessary-code-warnings">Unnecessary code warnings</a></li></ul></li><li class="toc-entry"><a href="#working-with-nullable-types">Working with nullable types</a><ul><li class="toc-entry"><a href="#smarter-null-aware-methods">Smarter null-aware methods</a></li><li class="toc-entry"><a href="#non-null-assertion-operator">Non-null assertion operator</a></li><li class="toc-entry"><a href="#late-variables">Late variables</a></li><li class="toc-entry"><a href="#lazy-initialization">Lazy initialization</a></li><li class="toc-entry"><a href="#late-final-variables">Late final variables</a></li><li class="toc-entry"><a href="#required-named-parameters">Required named parameters</a></li><li class="toc-entry"><a href="#abstract-fields">Abstract fields</a></li><li class="toc-entry"><a href="#working-with-nullable-fields">Working with nullable fields</a></li><li class="toc-entry"><a href="#nullability-and-generics">Nullability and generics</a></li></ul></li><li class="toc-entry"><a href="#core-library-changes">Core library changes</a><ul><li class="toc-entry"><a href="#the-map-index-operator-is-nullable">The Map index operator is nullable</a></li><li class="toc-entry"><a href="#no-unnamed-list-constructor">No unnamed List constructor</a></li><li class="toc-entry"><a href="#cannot-set-a-larger-length-on-non-nullable-lists">Cannot set a larger length on non-nullable lists</a></li><li class="toc-entry"><a href="#cannot-access-iterator-current-before-or-after-iteration">Cannot access Iterator.current before or after iteration</a></li></ul></li><li class="toc-entry"><a href="#summary">Summary</a></li></ul><span class="site-toc--inline__toggle toc-toggle-more-items"><i class="material-symbols">more_horiz</i></span></div><p><em>Written by Bob Nystrom<br>July 2020</em></p><p>Null safety is the largest change we've made to Dart since we replaced the original unsound optional type system with <a href="/language/type-system">a sound static type system</a> in Dart 2.0. When Dart first launched, compile-time null safety was a rare feature needing a long introduction. Today, Kotlin, Swift, Rust, and other languages all have their own answers to what has become a very <a href="https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare/">familiar problem.</a> Here is an example:</p><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:#6E6E70">// Without null safety:</span></span> <span class="line"><span style="color:#0468D7">bool</span><span style="color:#6200EE"> isEmpty</span><span style="color:#222222">(</span><span style="color:#0468D7">String</span><span style="color:#222222"> string) => string.length == </span><span style="color:#11796D">0</span><span style="color:#222222">;</span></span> <span class="line"></span> <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:#6200EE"> isEmpty</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></code></pre></div></div><p>If you run this Dart program without null safety, it throws a <code>NoSuchMethodError</code> exception on the call to <code>.length</code>. The <code>null</code> value is an instance of the <code>Null</code> class, and <code>Null</code> has no &quot;length&quot; getter. Runtime failures suck. This is especially true in a language like Dart that is designed to run on an end-user's device. If a server application fails, you can often restart it before anyone notices. But when a Flutter app crashes on a user's phone, they are not happy. When your users aren't happy, you aren't happy.</p><p>Developers like statically-typed languages like Dart because they enable the type checker to find mistakes in code at compile time, usually right in the IDE. The sooner you find a bug, the sooner you can fix it. When language designers talk about &quot;fixing null reference errors&quot;, they mean enriching the static type checker so that the language can detect mistakes like the above attempt to call <code>.length</code> on a value that might be <code>null</code>.</p><p>There is no one true solution to this problem. Rust and Kotlin both have their own approach that makes sense in the context of those languages. This doc walks through all the details of our answer for Dart. It includes changes to the static type system and a suite of other modifications and new language features to let you not only write null-safe code but hopefully to <em>enjoy</em> doing so.</p><p>This document is long. If you want something shorter that covers just what you need to know to get up and running, start with the <a href="/null-safety">overview</a>. When you are ready for a deeper understanding and have the time, come back here so you can understand <em>how</em> the language handles <code>null</code>, <em>why</em> we designed it that way, and how to write idiomatic, modern, null-safe Dart. (Spoiler alert: it ends up surprisingly close to how you write Dart today.)</p><p>The various ways a language can tackle null reference errors each have their pros and cons. These principles guided the choices we made:</p><ul><li><p><strong>Code should be safe by default.</strong> If you write new Dart code and don't use any explicitly unsafe features, it never throws a null reference error at runtime. All possible null reference errors are caught statically. If you want to defer some of that checking to runtime to get greater flexibility, you can, but you have to choose that by using some feature that is textually visible in the code.</p><p>In other words, we aren't giving you a life jacket and leaving it up to you to remember to put it on every time you go out on the water. Instead, we give you a boat that doesn't sink. You stay dry unless you jump overboard.</p></li><li><p><strong>Null-safe code should be easy to write.</strong> Most existing Dart code is dynamically correct and does not throw null reference errors. You like your Dart program the way it looks now, and we want you to be able to keep writing code that way. Safety shouldn't require sacrificing usability, paying penance to the type checker, or having to significantly change the way you think.</p></li><li><p><strong>The resulting null-safe code should be fully sound.</strong> &quot;Soundness&quot; in the context of static checking means different things to different people. For us, in the context of null safety, that means that if an expression has a static type that does not permit <code>null</code>, then no possible execution of that expression can ever evaluate to <code>null</code>. The language provides this guarantee mostly through static checks, but there can be some runtime checks involved too. (Though, note the first principle: any place where those runtime checks happen will be your choice.)</p><p>Soundness is important for user confidence. A boat that <em>mostly</em> stays afloat is not one you're enthused to brave the open seas on. But it's also important for our intrepid compiler hackers. When the language makes hard guarantees about semantic properties of a program, it means that the compiler can perform optimizations that assume those properties are true. When it comes to <code>null</code>, it means we can generate smaller code that eliminates unneeded <code>null</code> checks, and faster code that doesn't need to verify a receiver is non-<code>null</code> before calling methods on it.</p><p>One caveat: We only guarantee soundness in Dart programs that are fully null safe. Dart supports programs that contain a mixture of newer null-safe code and older legacy code. In these mixed-version programs, null reference errors may still occur. In a mixed-version program, you get all of the <em>static</em> safety benefits in the portions that are null safe, but you don't get full runtime soundness until the entire application is null safe.</p></li></ul><p>Note that <em>eliminating</em> <code>null</code> is not a goal. There's nothing wrong with <code>null</code>. On the contrary, it's really useful to be able to represent the <em>absence</em> of a value. Building support for a special &quot;absent&quot; value directly into the language makes working with absence flexible and usable. It underpins optional parameters, the handy <code>?.</code> null-aware operator, and default initialization. It is not <code>null</code> that is bad, it is having <code>null</code> go <em>where you don't expect it</em> that causes problems.</p><p>Thus with null safety, our goal is to give you <em>control</em> and <em>insight</em> into where <code>null</code> can flow through your program and certainty that it can't flow somewhere that would cause a crash.</p><div class="header-wrapper"><h2 id="nullability-in-the-type-system">Nullability in the type system</h2><a class="heading-link" href="#nullability-in-the-type-system" aria-label="Link to 'Nullability in the type system' section">#</a></div><p>Null safety begins in the static type system because everything else rests upon that. Your Dart program has a whole universe of types in it: primitive types like <code>int</code> and <code>String</code>, collection types like <code>List</code>, and all of the classes and types you and the packages you use define. Before null safety, the static type system allowed the value <code>null</code> to flow into expressions of any of those types.</p><p>In type theory lingo, the <code>Null</code> type was treated as a subtype of all types:</p><img src="/assets/img/null-safety/understanding-null-safety/hierarchy-before.png" alt="Null Safety Hierarchy Before" width="335"><p>The set of operations鈥攇etters, setters, methods, and operators鈥攁llowed on some expressions are defined by its type. If the type is <code>List</code>, you can call <code>.add()</code> or <code>[]</code> on it. If it's <code>int</code>, you can call <code>+</code>. But the <code>null</code> value doesn't define any of those methods. Allowing <code>null</code> to flow into an expression of some other type means any of those operations can fail. This is really the crux of null reference errors鈥攅very failure comes from trying to look up a method or property on <code>null</code> that it doesn't have.</p><div class="header-wrapper"><h3 id="non-nullable-and-nullable-types">Non-nullable and nullable types</h3><a class="heading-link" href="#non-nullable-and-nullable-types" aria-label="Link to 'Non-nullable and nullable types' section">#</a></div><p>Null safety eliminates that problem at the root by changing the type hierarchy. The <code>Null</code> type still exists, but it's no longer a subtype of all types. Instead, the type hierarchy looks like this:</p><img src="/assets/img/null-safety/understanding-null-safety/hierarchy-after.png" alt="Null Safety Hierarchy After" width="344"><p>Since <code>Null</code> is no longer a subtype, no type except the special <code>Null</code> class permits the value <code>null</code>. We've made all types <em>non-nullable by default</em>. If you have a variable of type <code>String</code>, it will always contain <em>a string</em>. There, we've fixed all null reference errors.</p><p>If we didn't think <code>null</code> was useful at all, we could stop here. But <code>null</code> is useful, so we still need a way to handle it. Optional parameters are a good illustrative case. Consider this null-safe Dart code:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> makeCoffee</span><span style="color:#222222">(</span><span style="color:#0468D7">String</span><span style="color:#222222"> coffee, [</span><span style="color:#0468D7">String</span><span style="color:#222222">? dairy]) {</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (dairy != </span><span style="color:#11796D">null</span><span style="color:#222222">) {</span></span> <span class="line"><span style="color:#6200EE"> print</span><span style="color:#222222">(</span><span style="color:#11796D">'</span><span style="color:#11796D">$</span><span style="color:#222222">coffee</span><span style="color:#11796D"> with </span><span style="color:#11796D">$</span><span style="color:#222222">dairy</span><span style="color:#11796D">'</span><span style="color:#222222">);</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">(</span><span style="color:#11796D">'Black </span><span style="color:#11796D">$</span><span style="color:#222222">coffee</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:#222222">}</span></span></code></pre></div></div><p>Here, we want to allow the <code>dairy</code> parameter to accept any string, or the value <code>null</code>, but nothing else. To express that, we give <code>dairy</code> a <em>nullable type</em> by slapping <code>?</code> at the end of the underlying base type <code>String</code>. Under the hood, this is essentially defining a <a href="https://en.wikipedia.org/wiki/Union_type">union</a> of the underlying type and the <code>Null</code> type. So <code>String?</code> would be a shorthand for <code>String|Null</code> if Dart had full-featured union types.</p><div class="header-wrapper"><h3 id="using-nullable-types">Using nullable types</h3><a class="heading-link" href="#using-nullable-types" aria-label="Link to 'Using nullable types' section">#</a></div><p>If you have an expression with a nullable type, what can you do with the result? Since our principle is safe by default, the answer is not much. We can't let you call methods of the underlying type on it because those might fail if the value is <code>null</code>:</p><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:#6E6E70">// Hypothetical unsound null safety:</span></span> <span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> bad</span><span style="color:#222222">(</span><span style="color:#0468D7">String</span><span style="color:#222222">? maybeString) {</span></span> <span class="line"><span style="color:#6200EE"> print</span><span style="color:#222222">(maybeString.length);</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"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#6200EE"> bad</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></code></pre></div></div><p>This would crash if we let you run it. The only methods and properties we can safely let you access are ones defined by both the underlying type and the <code>Null</code> class. That's just <code>toString()</code>, <code>==</code>, and <code>hashCode</code>. So you can use nullable types as map keys, store them in sets, compare them to other values, and use them in string interpolation, but that's about it.</p><p>How do they interact with non-nullable types? It's always safe to pass a <em>non</em>-nullable type to something expecting a nullable type. If a function accepts <code>String?</code> then passing a <code>String</code> is allowed because it won't cause any problems. We model this by making every nullable type a supertype of its underlying type. You can also safely pass <code>null</code> to something expecting a nullable type, so <code>Null</code> is also a subtype of every nullable type:</p><img src="/assets/img/null-safety/understanding-null-safety/nullable-hierarchy.png" alt="Nullable" width="235"><p>But going the other direction and passing a nullable type to something expecting the underlying non-nullable type is unsafe. Code that expects a <code>String</code> may call <code>String</code> methods on the value. If you pass a <code>String?</code> to it, <code>null</code> could flow in and that could fail:</p><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:#6E6E70">// Hypothetical unsound null safety:</span></span> <span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> requireStringNotNull</span><span style="color:#222222">(</span><span style="color:#0468D7">String</span><span style="color:#222222"> definitelyString) {</span></span> <span class="line"><span style="color:#6200EE"> print</span><span style="color:#222222">(definitelyString.length);</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"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#0468D7"> String</span><span style="color:#222222">? maybeString = </span><span style="color:#11796D">null</span><span style="color:#222222">; </span><span style="color:#6E6E70">// Or not!</span></span> <span class="line"><span style="color:#6200EE"> requireStringNotNull</span><span style="color:#222222">(maybeString);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>This program is not safe and we shouldn't allow it. However, Dart has always had this thing called <em>implicit downcasts</em>. If you, for example, pass a value of type <code>Object</code> to a function expecting a <code>String</code>, the type checker allows it:</p><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:#6E6E70">// Without null safety:</span></span> <span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> requireStringNotObject</span><span style="color:#222222">(</span><span style="color:#0468D7">String</span><span style="color:#222222"> definitelyString) {</span></span> <span class="line"><span style="color:#6200EE"> print</span><span style="color:#222222">(definitelyString.length);</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"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#0468D7"> Object</span><span style="color:#222222"> maybeString = </span><span style="color:#11796D">'it is'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#6200EE"> requireStringNotObject</span><span style="color:#222222">(maybeString);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>To maintain soundness, the compiler silently inserts an <code>as String</code> cast on the argument to <code>requireStringNotObject()</code>. That cast could fail and throw an exception at runtime, but at compile time, Dart says this is OK. Since non-nullable types are modeled as subtypes of nullable types, implicit downcasts would let you pass a <code>String?</code> to something expecting a <code>String</code>. Allowing that would violate our goal of being safe by default. So with null safety we are removing implicit downcasts entirely.</p><p>This makes the call to <code>requireStringNotNull()</code> produce a compile error, which is what you want. But it also means <em>all</em> implicit downcasts become compile errors, including the call to <code>requireStringNotObject()</code>. You'll have to add the explicit downcast yourself:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> requireStringNotObject</span><span style="color:#222222">(</span><span style="color:#0468D7">String</span><span style="color:#222222"> definitelyString) {</span></span> <span class="line"><span style="color:#6200EE"> print</span><span style="color:#222222">(definitelyString.length);</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"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#0468D7"> Object</span><span style="color:#222222"> maybeString = </span><span style="color:#11796D">'it is'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#6200EE"> requireStringNotObject</span><span style="color:#222222">(maybeString </span><span style="color:#D43324">as</span><span style="color:#0468D7"> String</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>We think this is an overall good change. Our impression is that most users never liked implicit downcasts. In particular, you may have been burned by this before:</p><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:#6E6E70">// Without null safety:</span></span> <span class="line"><span style="color:#0468D7">List</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">int</span><span style="color:#222222">> </span><span style="color:#6200EE">filterEvens</span><span style="color:#222222">(</span><span style="color:#0468D7">List</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">int</span><span style="color:#222222">> ints) {</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> ints.</span><span style="color:#6200EE">where</span><span style="color:#222222">((n) => n.isEven);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Spot the bug? The <code>.where()</code> method is lazy, so it returns an <code>Iterable</code>, not a <code>List</code>. This program compiles but then throws an exception at runtime when it tries to cast that <code>Iterable</code> to the <code>List</code> type that <code>filterEvens</code> declares it returns. With the removal of implicit downcasts, this becomes a compile error.</p><p>Where were we? Right, OK, so it's as if we've taken the universe of types in your program and split them into two halves:</p><img src="/assets/img/null-safety/understanding-null-safety/bifurcate.png" alt="Nullable and Non-Nullable types" width="668"><p>There is a region of non-nullable types. Those types let you access all of the interesting methods, but can never ever contain <code>null</code>. And then there is a parallel family of all of the corresponding nullable types. Those permit <code>null</code>, but you can't do much with them. We let values flow from the non-nullable side to the nullable side because doing so is safe, but not the other direction.</p><p>That seems like nullable types are basically useless. They have no methods and you can't get away from them. Don't worry, we have a whole suite of features to help you move values from the nullable half over to the other side that we will get to soon.</p><div class="header-wrapper"><h3 id="top-and-bottom">Top and bottom</h3><a class="heading-link" href="#top-and-bottom" aria-label="Link to 'Top and bottom' section">#</a></div><p>This section is a little esoteric. You can mostly skip it, except for two bullets at the very end, unless you're into type system stuff. Imagine all the types in your program with edges between ones that are subtypes and supertypes of each other. If you were to draw it, like the diagrams in this doc, it would form a huge directed graph with supertypes like <code>Object</code> near the top and leaf classes like your own types near the bottom.</p><p>If that directed graph comes to a point at the top where there is a single type that is the supertype (directly or indirectly), that type is called the <em>top type</em>. Likewise, if there is a weird type at that bottom that is a subtype of every type, you have a <em>bottom type</em>. (In this case, your directed graph is a <a href="https://en.wikipedia.org/wiki/Lattice_(order)">lattice.</a>)</p><p>It's convenient if your type system has a top and bottom type, because it means that type-level operations like least upper bound (which type inference uses to figure out the type of a conditional expression based on the types of its two branches) can always produce a type. Before null safety, <code>Object</code> was Dart's top type and <code>Null</code> was its bottom type.</p><p>Since <code>Object</code> is non-nullable now, it is no longer a top type. <code>Null</code> is not a subtype of it. Dart has no <em>named</em> top type. If you need a top type, you want <code>Object?</code>. Likewise, <code>Null</code> is no longer the bottom type. If it was, everything would still be nullable. Instead, we've added a new bottom type named <code>Never</code>:</p><img src="/assets/img/null-safety/understanding-null-safety/top-and-bottom.png" alt="Top and Bottom" width="360"><p>In practice, this means:</p><ul><li><p>If you want to indicate that you allow a value of any type, use <code>Object?</code> instead of <code>Object</code>. In fact, it becomes pretty unusual to use <code>Object</code> since that type means &quot;could be any possible value except this one weirdly prohibited value <code>null</code>&quot;.</p></li><li><p>On the rare occasion that you need a bottom type, use <code>Never</code> instead of <code>Null</code>. This is particularly useful to indicate a function never returns to <a href="#never-for-unreachable-code">help reachability analysis</a>. If you don't know if you need a bottom type, you probably don't.</p></li></ul><div class="header-wrapper"><h2 id="ensuring-correctness">Ensuring correctness</h2><a class="heading-link" href="#ensuring-correctness" aria-label="Link to 'Ensuring correctness' section">#</a></div><p>We divided the universe of types into nullable and non-nullable halves. In order to maintain soundness and our principle that you can never get a null reference error at runtime unless you ask for it, we need to guarantee that <code>null</code> never appears in any type on the non-nullable side.</p><p>Getting rid of implicit downcasts and removing <code>Null</code> as a bottom type covers all of the main places that types flow through a program across assignments and from arguments into parameters on function calls. The main remaining places where <code>null</code> can sneak in are when a variable first comes into being and when you leave a function. So there are some additional compile errors:</p><div class="header-wrapper"><h3 id="invalid-returns">Invalid returns</h3><a class="heading-link" href="#invalid-returns" aria-label="Link to 'Invalid returns' section">#</a></div><p>If a function has a non-nullable return type, then every path through the function must reach a <code>return</code> statement that returns a value. Before null safety, Dart was pretty lax about missing returns. For example:</p><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:#6E6E70">// Without null safety:</span></span> <span class="line"><span style="color:#0468D7">String</span><span style="color:#6200EE"> missingReturn</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#6E6E70"> // No return.</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>If you analyzed this, you got a gentle <em>hint</em> that <em>maybe</em> you forgot a return, but if not, no big deal. That's because if execution reaches the end of a function body then Dart implicitly returns <code>null</code>. Since every type is nullable, <em>technically</em> this function is safe, even though it's probably not what you want.</p><p>With sound non-nullable types, this program is flat out wrong and unsafe. Under null safety, you get a compile error if a function with a non-nullable return type doesn't reliably return a value. By &quot;reliably&quot;, I mean that the language analyzes all of the control flow paths through the function. As long as they all return something, it is satisfied. The analysis is pretty smart, so even this function is OK:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#0468D7">String</span><span style="color:#6200EE"> alwaysReturns</span><span style="color:#222222">(</span><span style="color:#0468D7">int</span><span style="color:#222222"> n) {</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (n == </span><span style="color:#11796D">0</span><span style="color:#222222">) {</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#11796D"> 'zero'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222"> } </span><span style="color:#D43324">else</span><span style="color:#D43324"> if</span><span style="color:#222222"> (n &#x3C; </span><span style="color:#11796D">0</span><span style="color:#222222">) {</span></span> <span class="line"><span style="color:#D43324"> throw</span><span style="color:#0468D7"> ArgumentError</span><span style="color:#222222">(</span><span style="color:#11796D">'Negative values not allowed.'</span><span style="color:#222222">);</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"> if</span><span style="color:#222222"> (n > </span><span style="color:#11796D">1000</span><span style="color:#222222">) {</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#11796D"> 'big'</span><span style="color:#222222">;</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"> return</span><span style="color:#222222"> n.</span><span style="color:#6200EE">toString</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><p>We'll dive more deeply into the new flow analysis in the next section.</p><div class="header-wrapper"><h3 id="uninitialized-variables">Uninitialized variables</h3><a class="heading-link" href="#uninitialized-variables" aria-label="Link to 'Uninitialized variables' section">#</a></div><p>When you declare a variable, if you don't give it an explicit initializer, Dart default initializes the variable with <code>null</code>. That's convenient, but obviously totally unsafe if the variable's type is non-nullable. So we have to tighten things up for non-nullable variables:</p><ul><li><p><strong>Top level variable and static field declarations must have an initializer.</strong> Since these can be accessed and assigned from anywhere in the program, it's impossible for the compiler to guarantee that the variable has been given a value before it gets used. The only safe option is to require the declaration itself to have an initializing expression that produces a value of the right type:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#0468D7">int</span><span style="color:#222222"> topLevel = </span><span style="color:#11796D">0</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> SomeClass</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> static</span><span style="color:#0468D7"> int</span><span style="color:#222222"> staticField = </span><span style="color:#11796D">0</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div></li><li><p><strong>Instance fields must either have an initializer at the declaration, use an initializing formal, or be initialized in the constructor's initialization list.</strong> That's a lot of jargon. Here are the examples:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> SomeClass</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#0468D7"> int</span><span style="color:#222222"> atDeclaration = </span><span style="color:#11796D">0</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#0468D7"> int</span><span style="color:#222222"> initializingFormal;</span></span> <span class="line"><span style="color:#0468D7"> int</span><span style="color:#222222"> initializationList;</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> SomeClass</span><span style="color:#222222">(</span><span style="color:#D43324">this</span><span style="color:#222222">.initializingFormal)</span></span> <span class="line"><span style="color:#222222"> : initializationList = </span><span style="color:#11796D">0</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>In other words, as long as the field has a value before you reach the constructor body, you're good.</p></li><li><p>Local variables are the most flexible case. A non-nullable local variable <em>doesn't</em> need to have an initializer. This is perfectly fine:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#0468D7">int</span><span style="color:#6200EE"> tracingFibonacci</span><span style="color:#222222">(</span><span style="color:#0468D7">int</span><span style="color:#222222"> n) {</span></span> <span class="line"><span style="color:#0468D7"> int</span><span style="color:#222222"> result;</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (n &#x3C; </span><span style="color:#11796D">2</span><span style="color:#222222">) {</span></span> <span class="line"><span style="color:#222222"> result = n;</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:#222222"> result = </span><span style="color:#6200EE">tracingFibonacci</span><span style="color:#222222">(n - </span><span style="color:#11796D">2</span><span style="color:#222222">) + </span><span style="color:#6200EE">tracingFibonacci</span><span style="color:#222222">(n - </span><span style="color:#11796D">1</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:#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></code></pre></div></div><p>The rule is only that <strong>a local variable must be <em>definitely assigned</em> before it is used.</strong> We get to rely on the new flow analysis I alluded to for this as well. As long as every path to a variable's use initializes it first, the use is OK.</p></li><li><p><strong>Optional parameters must have a default value.</strong> If you don't pass an argument for an optional positional or named parameter, then the language fills it in with the default value. If you don't specify a default value, the <em>default</em> default value is <code>null</code>, and that doesn't fly if the parameter's type is non-nullable.</p><p>So, if you want a parameter to be optional, you need to either make it nullable or specify a valid non-<code>null</code> default value.</p></li></ul><p>These restrictions sound onerous, but they aren't too bad in practice. They are very similar to the existing restrictions around <code>final</code> variables and you've likely been working with those for years without even really noticing. Also, remember that these only apply to <em>non-nullable</em> variables. You can always make the type nullable and then get the default initialization to <code>null</code>.</p><p>Even so, the rules do cause friction. Fortunately, we have a suite of new language features to lubricate the most common patterns where these new limitations slow you down. First, though, it's time to talk about flow analysis.</p><div class="header-wrapper"><h2 id="flow-analysis">Flow analysis</h2><a class="heading-link" href="#flow-analysis" aria-label="Link to 'Flow analysis' section">#</a></div><p><a href="https://en.wikipedia.org/wiki/Control_flow_analysis">Control flow analysis</a> has been around in compilers for years. It's mostly hidden from users and used during compiler optimization, but some newer languages have started to use the same techniques for visible language features. Dart already has a dash of flow analysis in the form of <em>type promotion</em>:</p><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:#6E6E70">// With (or without) null safety:</span></span> <span class="line"><span style="color:#0468D7">bool</span><span style="color:#6200EE"> isEmptyList</span><span style="color:#222222">(</span><span style="color:#0468D7">Object</span><span style="color:#222222"> object) {</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (object is </span><span style="color:#0468D7">List</span><span style="color:#222222">) {</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> object.isEmpty; </span><span style="color:#6E6E70">// &#x3C;-- OK!</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"> return</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>Note how on the marked line, we can call <code>isEmpty</code> on <code>object</code>. That method is defined on <code>List</code>, not <code>Object</code>. This works because the type checker looks at all of the <code>is</code> expressions and the control flow paths in the program. If the body of some control flow construct only executes when a certain <code>is</code> expression on a variable is true, then inside that body the variable's type is &quot;promoted&quot; to the tested type.</p><p>In the example here, the then branch of the <code>if</code> statement only runs when <code>object</code> actually contains a list. Therefore, Dart promotes <code>object</code> to type <code>List</code> instead of its declared type <code>Object</code>. This is a handy feature, but it's pretty limited. Prior to null safety, the following functionally identical program did not work:</p><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:#6E6E70">// Without null safety:</span></span> <span class="line"><span style="color:#0468D7">bool</span><span style="color:#6200EE"> isEmptyList</span><span style="color:#222222">(</span><span style="color:#0468D7">Object</span><span style="color:#222222"> object) {</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (object is! </span><span style="color:#0468D7">List</span><span style="color:#222222">) </span><span style="color:#D43324">return</span><span style="color:#11796D"> false</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> object.isEmpty; </span><span style="color:#6E6E70">// &#x3C;-- Error!</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Again, you can only reach the <code>.isEmpty</code> call when <code>object</code> contains a list, so this program is dynamically correct. But the type promotion rules were not smart enough to see that the <code>return</code> statement means the second statement can only be reached when <code>object</code> is a list.</p><p>For null safety, we've taken this limited analysis and made it <a href="https://github.com/dart-lang/language/blob/main/resources/type-system/flow-analysis.md">much more powerful in several ways.</a></p><div class="header-wrapper"><h3 id="reachability-analysis">Reachability analysis</h3><a class="heading-link" href="#reachability-analysis" aria-label="Link to 'Reachability analysis' section">#</a></div><p>First off, we fixed the <a href="https://github.com/dart-lang/sdk/issues/18921">long-standing complaint</a> that type promotion isn't smart about early returns and other unreachable code paths. When analyzing a function, it now takes into account <code>return</code>, <code>break</code>, <code>throw</code>, and any other way execution might terminate early in a function. Under null safety, this function:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#0468D7">bool</span><span style="color:#6200EE"> isEmptyList</span><span style="color:#222222">(</span><span style="color:#0468D7">Object</span><span style="color:#222222"> object) {</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (object is! </span><span style="color:#0468D7">List</span><span style="color:#222222">) </span><span style="color:#D43324">return</span><span style="color:#11796D"> false</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> object.isEmpty;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Is now perfectly valid. Since the <code>if</code> statement will exit the function when <code>object</code> is <em>not</em> a <code>List</code>, Dart promotes <code>object</code> to be <code>List</code> on the second statement. This is a really nice improvement that helps a lot of Dart code, even stuff not related to nullability.</p><div class="header-wrapper"><h3 id="never-for-unreachable-code">Never for unreachable code</h3><a class="heading-link" href="#never-for-unreachable-code" aria-label="Link to 'Never for unreachable code' section">#</a></div><p>You can also <em>program</em> this reachability analysis. The new bottom type <code>Never</code> has no values. (What kind of value is simultaneously a <code>String</code>, <code>bool</code>, and <code>int</code>?) So what does it mean for an expression to have type <code>Never</code>? It means that expression can never successfully finish evaluating. It must throw an exception, abort, or otherwise ensure that the surrounding code expecting the result of the expression never runs.</p><p>In fact, according to the language, the static type of a <code>throw</code> expression is <code>Never</code>. The type <code>Never</code> is declared in the core libraries and you can use it as a type annotation. Maybe you have a helper function to make it easier to throw a certain kind of exception:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#0468D7">Never</span><span style="color:#6200EE"> wrongType</span><span style="color:#222222">(</span><span style="color:#0468D7">String</span><span style="color:#222222"> type, </span><span style="color:#0468D7">Object</span><span style="color:#222222"> value) {</span></span> <span class="line"><span style="color:#D43324"> throw</span><span style="color:#0468D7"> ArgumentError</span><span style="color:#222222">(</span><span style="color:#11796D">'Expected </span><span style="color:#11796D">$</span><span style="color:#222222">type</span><span style="color:#11796D">, but was </span><span style="color:#11796D">${</span><span style="color:#222222">value</span><span style="color:#11796D">.</span><span style="color:#222222">runtimeType</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></code></pre></div></div><p>You might use it like so:</p><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:#6E6E70">// Using null safety:</span></span> <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"> final</span><span style="color:#0468D7"> double</span><span style="color:#222222"> x, y;</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> bool</span><span style="color:#D43324"> operator</span><span style="color:#222222"> ==(</span><span style="color:#0468D7">Object</span><span style="color:#222222"> other) {</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (other is! </span><span style="color:#0468D7">Point</span><span style="color:#222222">) </span><span style="color:#6200EE">wrongType</span><span style="color:#222222">(</span><span style="color:#11796D">'Point'</span><span style="color:#222222">, other);</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> x == other.x &#x26;&#x26; y == other.y;</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70"> // Constructor and hashCode...</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>This program analyzes without error. Notice that the last line of the <code>==</code> method accesses <code>.x</code> and <code>.y</code> on <code>other</code>. It has been promoted to <code>Point</code> even though the function doesn't have any <code>return</code> or <code>throw</code>. The control flow analysis knows that the declared type of <code>wrongType()</code> is <code>Never</code> which means the then branch of the <code>if</code> statement <em>must</em> abort somehow. Since the second statement can only be reached when <code>other</code> is a <code>Point</code>, Dart promotes it.</p><p>In other words, using <code>Never</code> in your own APIs lets you extend Dart's reachability analysis.</p><div class="header-wrapper"><h3 id="definite-assignment-analysis">Definite assignment analysis</h3><a class="heading-link" href="#definite-assignment-analysis" aria-label="Link to 'Definite assignment analysis' section">#</a></div><p>I mentioned this one briefly with local variables. Dart needs to ensure a non-nullable local variable is always initialized before it is read. We use <em>definite assignment analysis</em> to be as flexible about that as possible. The language analyzes each function body and tracks the assignments to local variables and parameters through all control flow paths. As long as the variable is assigned on every path that reaches some use of a variable, the variable is considered initialized. This lets you declare a variable with no initializer and then initialize it afterwards using complex control flow, even when the variable has a non-nullable type.</p><p>We also use definite assignment analysis to make <em>final</em> variables more flexible. Before null safety, it can be difficult to use <code>final</code> for local variables if you need to initialize them in any sort of interesting way:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#0468D7">int</span><span style="color:#6200EE"> tracingFibonacci</span><span style="color:#222222">(</span><span style="color:#0468D7">int</span><span style="color:#222222"> n) {</span></span> <span class="line"><span style="color:#D43324"> final</span><span style="color:#0468D7"> int</span><span style="color:#222222"> result;</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (n &#x3C; </span><span style="color:#11796D">2</span><span style="color:#222222">) {</span></span> <span class="line"><span style="color:#222222"> result = n;</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:#222222"> result = </span><span style="color:#6200EE">tracingFibonacci</span><span style="color:#222222">(n - </span><span style="color:#11796D">2</span><span style="color:#222222">) + </span><span style="color:#6200EE">tracingFibonacci</span><span style="color:#222222">(n - </span><span style="color:#11796D">1</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:#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></code></pre></div></div><p>This would be an error since the <code>result</code> variable is <code>final</code> but has no initializer. With the smarter flow analysis under null safety, this program is fine. The analysis can tell that <code>result</code> is definitely initialized exactly once on every control flow path, so the constraints for marking a variable <code>final</code> are satisfied.</p><div class="header-wrapper"><h3 id="type-promotion-on-null-checks">Type promotion on null checks</h3><a class="heading-link" href="#type-promotion-on-null-checks" aria-label="Link to 'Type promotion on null checks' section">#</a></div><p>The smarter flow analysis helps lots of Dart code, even code not related to nullability. But it's not a coincidence that we're making these changes now. We have partitioned types into nullable and non-nullable sets. If you have a value of a nullable type, you can't really <em>do</em> anything useful with it. In cases where the value <em>is</em> <code>null</code>, that restriction is good. It's preventing you from crashing.</p><p>But if the value isn't <code>null</code>, it would be good to be able to move it over to the non-nullable side so you can call methods on it. Flow analysis is one of the primary ways to do this for local variables and parameters (and private final fields, as of Dart 3.2). We've extended type promotion to also look at <code>== null</code> and <code>!= null</code> expressions.</p><p>If you check a local variable with nullable type to see if it is not <code>null</code>, Dart then promotes the variable to the underlying non-nullable type:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#0468D7">String</span><span style="color:#6200EE"> makeCommand</span><span style="color:#222222">(</span><span style="color:#0468D7">String</span><span style="color:#222222"> executable, [</span><span style="color:#0468D7">List</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">String</span><span style="color:#222222">>? arguments]) {</span></span> <span class="line"><span style="color:#D43324"> var</span><span style="color:#222222"> result = executable;</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (arguments != </span><span style="color:#11796D">null</span><span style="color:#222222">) {</span></span> <span class="line"><span style="color:#222222"> result += </span><span style="color:#11796D">' '</span><span style="color:#222222"> + arguments.</span><span style="color:#6200EE">join</span><span style="color:#222222">(</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:#222222"> result;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Here, <code>arguments</code> has a nullable type. Normally, that prohibits you from calling <code>.join()</code> on it. But because we have guarded that call in an <code>if</code> statement that checks to ensure the value is not <code>null</code>, Dart promotes it from <code>List&lt;String&gt;?</code> to <code>List&lt;String&gt;</code> and lets you call methods on it or pass it to functions that expect non-nullable lists.</p><p>This sounds like a fairly minor thing, but this flow-based promotion on null checks is what makes most existing Dart code work under null safety. Most Dart code <em>is</em> dynamically correct and does avoid throwing null reference errors by checking for <code>null</code> before calling methods. The new flow analysis on null checks turns that <em>dynamic</em> correctness into provable <em>static</em> correctness.</p><p>It also, of course, works with the smarter analysis we do for reachability. The above function can be written just as well as:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#0468D7">String</span><span style="color:#6200EE"> makeCommand</span><span style="color:#222222">(</span><span style="color:#0468D7">String</span><span style="color:#222222"> executable, [</span><span style="color:#0468D7">List</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">String</span><span style="color:#222222">>? arguments]) {</span></span> <span class="line"><span style="color:#D43324"> var</span><span style="color:#222222"> result = executable;</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (arguments == </span><span style="color:#11796D">null</span><span style="color:#222222">) </span><span style="color:#D43324">return</span><span style="color:#222222"> result;</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> result + </span><span style="color:#11796D">' '</span><span style="color:#222222"> + arguments.</span><span style="color:#6200EE">join</span><span style="color:#222222">(</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>The language is also smarter about what kinds of expressions cause promotion. An explicit <code>== null</code> or <code>!= null</code> of course works. But explicit casts using <code>as</code>, or assignments, or the postfix <code>!</code> operator (which we'll cover <a href="#non-null-assertion-operator">later on</a>) also cause promotion. The general goal is that if the code is dynamically correct and it's reasonable to figure that out statically, the analysis should be clever enough to do so.</p><p>Note that type promotion originally only worked on local variables, and now also works on private final fields as of Dart 3.2. For more information about working with non-local variables, see <a href="#working-with-nullable-fields">Working with nullable fields</a>.</p><div class="header-wrapper"><h3 id="unnecessary-code-warnings">Unnecessary code warnings</h3><a class="heading-link" href="#unnecessary-code-warnings" aria-label="Link to 'Unnecessary code warnings' section">#</a></div><p>Having smarter reachability analysis and knowing where <code>null</code> can flow through your program helps ensure that you <em>add</em> code to handle <code>null</code>. But we can also use that same analysis to detect code that you <em>don't</em> need. Before null safety, if you wrote something like:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#0468D7">String</span><span style="color:#6200EE"> checkList</span><span style="color:#222222">(</span><span style="color:#0468D7">List</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">Object</span><span style="color:#222222">> list) {</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (list?.isEmpty ?? </span><span style="color:#11796D">false</span><span style="color:#222222">) {</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#11796D"> 'Got nothing'</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"> 'Got something'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Dart had no way of knowing if that null-aware <code>?.</code> operator is useful or not. For all it knows, you could pass <code>null</code> to the function. But in null-safe Dart, if you have annotated that function with the now non-nullable <code>List</code> type, then it knows <code>list</code> will never be <code>null</code>. That implies the <code>?.</code> will never do anything useful and you can and should just use <code>.</code>.</p><p>To help you simplify your code, we've added warnings for unnecessary code like this now that the static analysis is precise enough to detect it. Using a null-aware operator or even a check like <code>== null</code> or <code>!= null</code> on a non-nullable type gets reported as a warning.</p><p>And, of course, this plays with non-nullable type promotion too. Once a variable has been promoted to a non-nullable type, you get a warning if you redundantly check it again for <code>null</code>:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#0468D7">String</span><span style="color:#6200EE"> checkList</span><span style="color:#222222">(</span><span style="color:#0468D7">List</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">Object</span><span style="color:#222222">>? list) {</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (list == </span><span style="color:#11796D">null</span><span style="color:#222222">) </span><span style="color:#D43324">return</span><span style="color:#11796D"> 'No list'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (list?.isEmpty ?? </span><span style="color:#11796D">false</span><span style="color:#222222">) {</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#11796D"> 'Empty list'</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"> 'Got something'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>You get a warning on the <code>?.</code> here because at the point that it executes, we already know <code>list</code> cannot be <code>null</code>. The goal with these warnings is not just to clean up pointless code. By removing <em>unneeded</em> checks for <code>null</code>, we ensure that the remaining meaningful checks stand out. We want you to be able to look at your code and <em>see</em> where <code>null</code> can flow.</p><div class="header-wrapper"><h2 id="working-with-nullable-types">Working with nullable types</h2><a class="heading-link" href="#working-with-nullable-types" aria-label="Link to 'Working with nullable types' section">#</a></div><p>We've now corralled <code>null</code> into the set of nullable types. With flow analysis, we can safely let some non-<code>null</code> values hop over the fence to the non-nullable side where we can use them. That's a big step, but if we stop here, the resulting system is still painfully restrictive. Flow analysis only helps with locals, parameters, and private final fields.</p><p>To try to regain as much of the flexibility that Dart had before null safety鈥攁nd to go beyond it in some places鈥攚e have a handful of other new features.</p><div class="header-wrapper"><h3 id="smarter-null-aware-methods">Smarter null-aware methods</h3><a class="heading-link" href="#smarter-null-aware-methods" aria-label="Link to 'Smarter null-aware methods' section">#</a></div><p>Dart's null aware operator <code>?.</code> is much older than null safety. The runtime semantics state that if the receiver is <code>null</code> then the property access on the right-hand side is skipped and the expression evaluates to <code>null</code>:</p><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:#6E6E70">// Without null safety:</span></span> <span class="line"><span style="color:#0468D7">String</span><span style="color:#222222"> notAString = </span><span style="color:#11796D">null</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#6200EE">print</span><span style="color:#222222">(notAString?.length);</span></span></code></pre></div></div><p>Instead of throwing an exception, this prints &quot;null&quot;. The null-aware operator is a nice tool for making nullable types usable in Dart. While we can't let you call methods on nullable types, we can and do let you use null-aware operators on them. The post-null safety version of the program is:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#0468D7">String</span><span style="color:#222222">? notAString = </span><span style="color:#11796D">null</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#6200EE">print</span><span style="color:#222222">(notAString?.length);</span></span></code></pre></div></div><p>It works just like the previous one.</p><p>However, if you've ever used null-aware operators in Dart, you've probably encountered an annoyance when using them in method chains. Let's say you want to see if the length of a potentially absent string is an even number (not a particularly realistic problem, I know, but work with me here):</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#0468D7">String</span><span style="color:#222222">? notAString = </span><span style="color:#11796D">null</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#6200EE">print</span><span style="color:#222222">(notAString?.length.isEven);</span></span></code></pre></div></div><p>Even though this program uses <code>?.</code>, it still throws an exception at runtime. The problem is that the receiver of the <code>.isEven</code> expression is the result of the entire <code>notAString?.length</code> expression to its left. That expression evaluates to <code>null</code>, so we get a null reference error trying to call <code>.isEven</code>. If you've ever used <code>?.</code> in Dart, you probably learned the hard way that you have to apply the null-aware operator to <em>every</em> property or method in a chain after you use it once:</p><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:#0468D7">String</span><span style="color:#222222">? notAString = </span><span style="color:#11796D">null</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#6200EE">print</span><span style="color:#222222">(notAString?.length?.isEven);</span></span></code></pre></div></div><p>This is annoying, but, worse, it obscures important information. Consider:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#6200EE">showGizmo</span><span style="color:#222222">(</span><span style="color:#0468D7">Thing</span><span style="color:#222222">? thing) {</span></span> <span class="line"><span style="color:#6200EE"> print</span><span style="color:#222222">(thing?.doohickey?.gizmo);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Here's a question for you: Can the <code>doohickey</code> getter on <code>Thing</code> return <code>null</code>? It looks like it <em>could</em> because you're using <code>?.</code> on the result. But it may just be that the second <code>?.</code> is only there to handle cases where <code>thing</code> is <code>null</code>, not the result of <code>doohickey</code>. You can't tell.</p><p>To address this, we borrowed a smart idea from C#'s design of the same feature. When you use a null-aware operator in a method chain, if the receiver evaluates to <code>null</code>, then <em>the entire rest of the method chain is short-circuited and skipped</em>. This means if <code>doohickey</code> has a non-nullable return type, then you can and should write:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> showGizmo</span><span style="color:#222222">(</span><span style="color:#0468D7">Thing</span><span style="color:#222222">? thing) {</span></span> <span class="line"><span style="color:#6200EE"> print</span><span style="color:#222222">(thing?.doohickey.gizmo);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>In fact, you'll get an unnecessary code warning on the second <code>?.</code> if you don't. If you see code like:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> showGizmo</span><span style="color:#222222">(</span><span style="color:#0468D7">Thing</span><span style="color:#222222">? thing) {</span></span> <span class="line"><span style="color:#6200EE"> print</span><span style="color:#222222">(thing?.doohickey?.gizmo);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Then you know for certain it means that <code>doohickey</code> itself has a nullable return type. Each <code>?.</code> corresponds to a <em>unique</em> path that can cause <code>null</code> to flow into the method chain. This makes null-aware operators in method chains both more terse and more precise.</p><p>While we were at it, we added a couple of other null-aware operators:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">// Null-aware cascade:</span></span> <span class="line"><span style="color:#222222">receiver?..</span><span style="color:#6200EE">method</span><span style="color:#222222">();</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">// Null-aware index operator:</span></span> <span class="line"><span style="color:#222222">receiver?[index];</span></span></code></pre></div></div><p>There isn't a null-aware function call operator, but you can write:</p><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:#6E6E70">// Allowed with or without null safety:</span></span> <span class="line"><span style="color:#222222">function?.</span><span style="color:#6200EE">call</span><span style="color:#222222">(arg1, arg2);</span></span></code></pre></div></div><p><a id="null-assertion-operator"></a></p><div class="header-wrapper"><h3 id="non-null-assertion-operator">Non-null assertion operator</h3><a class="heading-link" href="#non-null-assertion-operator" aria-label="Link to 'Non-null assertion operator' section">#</a></div><p>The great thing about using flow analysis to move a nullable variable to the non-nullable side of the world is that doing so is provably safe. You get to call methods on the previously-nullable variable without giving up any of the safety or performance of non-nullable types.</p><p>But many valid uses of nullable types can't be <em>proven</em> to be safe in a way that pleases static analysis. For example:</p><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:#6E6E70">// Using null safety, incorrectly:</span></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> HttpResponse</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"> code;</span></span> <span class="line"><span style="color:#D43324"> final</span><span style="color:#0468D7"> String</span><span style="color:#222222">? error;</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> HttpResponse</span><span style="color:#222222">.</span><span style="color:#6200EE">ok</span><span style="color:#222222">()</span></span> <span class="line"><span style="color:#222222"> : code = </span><span style="color:#11796D">200</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> error = </span><span style="color:#11796D">null</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#0468D7"> HttpResponse</span><span style="color:#222222">.</span><span style="color:#6200EE">notFound</span><span style="color:#222222">()</span></span> <span class="line"><span style="color:#222222"> : code = </span><span style="color:#11796D">404</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222"> error = </span><span style="color:#11796D">'Not found'</span><span style="color:#222222">;</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"> (code == </span><span style="color:#11796D">200</span><span style="color:#222222">) </span><span style="color:#D43324">return</span><span style="color:#11796D"> 'OK'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#11796D"> 'ERROR </span><span style="color:#11796D">$</span><span style="color:#222222">code</span><span style="color:#11796D"> ${</span><span style="color:#222222">error</span><span style="color:#11796D">.</span><span style="color:#6200EE">toUpperCase</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:#222222">}</span></span></code></pre></div></div><p>If you try to run this, you get a compile error on the call to <code>toUpperCase()</code>. The <code>error</code> field is nullable because it won't have a value in a successful response. We can see by inspecting the class that we never access the <code>error</code> message when it is <code>null</code>. But that requires understanding the relationship between the value of <code>code</code> and the nullability of <code>error</code>. The type checker can't see that connection.</p><p>In other words, we human maintainers of the code <em>know</em> that error won't be <code>null</code> at the point that we use it and we need a way to assert that. Normally, you assert types using an <code>as</code> cast, and you can do the same thing here:</p><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:#6E6E70">// Using null safety:</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"> (code == </span><span style="color:#11796D">200</span><span style="color:#222222">) </span><span style="color:#D43324">return</span><span style="color:#11796D"> 'OK'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#11796D"> 'ERROR </span><span style="color:#11796D">$</span><span style="color:#222222">code</span><span style="color:#11796D"> ${(</span><span style="color:#222222">error</span><span style="color:#222222"> as</span><span style="color:#0468D7"> String</span><span style="color:#11796D">).</span><span style="color:#6200EE">toUpperCase</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></code></pre></div></div><p>Casting <code>error</code> to the non-nullable <code>String</code> type will throw a runtime exception if the cast fails. Otherwise, it gives us a non-nullable string that we can then call methods on.</p><p>&quot;Casting away nullability&quot; comes up often enough that we have a new shorthand syntax. A postfix exclamation mark (<code>!</code>) takes the expression on the left and casts it to its underlying non-nullable type. So the above function is equivalent to:</p><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:#6E6E70">// Using null safety:</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"> (code == </span><span style="color:#11796D">200</span><span style="color:#222222">) </span><span style="color:#D43324">return</span><span style="color:#11796D"> 'OK'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#11796D"> 'ERROR </span><span style="color:#11796D">$</span><span style="color:#222222">code</span><span style="color:#11796D"> ${</span><span style="color:#222222">error</span><span style="color:#11796D">!.</span><span style="color:#6200EE">toUpperCase</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></code></pre></div></div><p>This one-character &quot;bang operator&quot; is particularly handy when the underlying type is verbose. It would be really annoying to have to write <code>as Map&lt;TransactionProviderFactory, List&lt;Set&lt;ResponseFilter&gt;&gt;&gt;</code> just to cast away a single <code>?</code> from some type.</p><p>Of course, like any cast, using <code>!</code> comes with a loss of static safety. The cast must be checked at runtime to preserve soundness and it may fail and throw an exception. But you have control over where these casts are inserted, and you can always see them by looking through your code.</p><div class="header-wrapper"><h3 id="late-variables">Late variables</h3><a class="heading-link" href="#late-variables" aria-label="Link to 'Late variables' section">#</a></div><p>The most common place where the type checker cannot prove the safety of code is around top-level variables and fields. Here is an example:</p><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:#6E6E70">// Using null safety, incorrectly:</span></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Coffee</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#0468D7"> String</span><span style="color:#222222"> _temperature;</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> heat</span><span style="color:#222222">() { _temperature = </span><span style="color:#11796D">'hot'</span><span style="color:#222222">; }</span></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> chill</span><span style="color:#222222">() { _temperature = </span><span style="color:#11796D">'iced'</span><span style="color:#222222">; }</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> String</span><span style="color:#6200EE"> serve</span><span style="color:#222222">() => _temperature + </span><span style="color:#11796D">' coffee'</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"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#D43324"> var</span><span style="color:#222222"> coffee = </span><span style="color:#0468D7">Coffee</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222"> coffee.</span><span style="color:#6200EE">heat</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222"> coffee.</span><span style="color:#6200EE">serve</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Here, the <code>heat()</code> method is called before <code>serve()</code>. That means <code>_temperature</code> will be initialized to a non-null value before it is used. But it's not feasible for a static analysis to determine that. (It might be possible for a trivial example like this one, but the general case of trying to track the state of each instance of a class is intractable.)</p><p>Because the type checker can't analyze uses of fields and top-level variables, it has a conservative rule that non-nullable fields have to be initialized either at their declaration (or in the constructor initialization list for instance fields). So Dart reports a compile error on this class.</p><p>You can fix the error by making the field nullable and then using null assertion operators on the uses:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Coffee</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#0468D7"> String</span><span style="color:#222222">? _temperature;</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> heat</span><span style="color:#222222">() { _temperature = </span><span style="color:#11796D">'hot'</span><span style="color:#222222">; }</span></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> chill</span><span style="color:#222222">() { _temperature = </span><span style="color:#11796D">'iced'</span><span style="color:#222222">; }</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> String</span><span style="color:#6200EE"> serve</span><span style="color:#222222">() => _temperature! + </span><span style="color:#11796D">' coffee'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>This works fine. But it sends a confusing signal to the maintainer of the class. By marking <code>_temperature</code> nullable, you imply that <code>null</code> is a useful, meaningful value for that field. But that's not the intent. The <code>_temperature</code> field should never be <em>observed</em> in its <code>null</code> state.</p><p>To handle the common pattern of state with delayed initialization, we've added a new modifier, <code>late</code>. You can use it like this:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Coffee</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> late</span><span style="color:#0468D7"> String</span><span style="color:#222222"> _temperature;</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> heat</span><span style="color:#222222">() { _temperature = </span><span style="color:#11796D">'hot'</span><span style="color:#222222">; }</span></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> chill</span><span style="color:#222222">() { _temperature = </span><span style="color:#11796D">'iced'</span><span style="color:#222222">; }</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> String</span><span style="color:#6200EE"> serve</span><span style="color:#222222">() => _temperature + </span><span style="color:#11796D">' coffee'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Note that the <code>_temperature</code> field has a non-nullable type, but is not initialized. Also, there's no explicit null assertion when it's used. There are a few models you can apply to the semantics of <code>late</code>, but I think of it like this: The <code>late</code> modifier means &quot;enforce this variable's constraints at runtime instead of at compile time&quot;. It's almost like the word &quot;late&quot; describes <em>when</em> it enforces the variable's guarantees.</p><p>In this case, since the field is not definitely initialized, every time the field is read, a runtime check is inserted to make sure it has been assigned a value. If it hasn't, an exception is thrown. Giving the variable the type <code>String</code> means &quot;you should never see me with a value other than a string&quot; and the <code>late</code> modifier means &quot;verify that at runtime&quot;.</p><p>In some ways, the <code>late</code> modifier is more &quot;magical&quot; than using <code>?</code> because any use of the field could fail, and there isn't anything textually visible at the use site. But you <em>do</em> have to write <code>late</code> at the declaration to get this behavior, and our belief is that seeing the modifier there is explicit enough for this to be maintainable.</p><p>In return, you get better static safety than using a nullable type. Because the field's type is non-nullable now, it is a <em>compile</em> error to try to assign <code>null</code> or a nullable <code>String</code> to the field. The <code>late</code> modifier lets you <em>defer</em> initialization, but still prohibits you from treating it like a nullable variable.</p><div class="header-wrapper"><h3 id="lazy-initialization">Lazy initialization</h3><a class="heading-link" href="#lazy-initialization" aria-label="Link to 'Lazy initialization' section">#</a></div><p>The <code>late</code> modifier has some other special powers too. It may seem paradoxical, but you can use <code>late</code> on a field that has an initializer:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Weather</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> late</span><span style="color:#0468D7"> int</span><span style="color:#222222"> _temperature = </span><span style="color:#6200EE">_readThermometer</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>When you do this, the initializer becomes <em>lazy</em>. Instead of running it as soon as the instance is constructed, it is deferred and run lazily the first time the field is accessed. In other words, it works exactly like an initializer on a top-level variable or static field. This can be handy when the initialization expression is costly and may not be needed.</p><p>Running the initializer lazily gives you an extra bonus when you use <code>late</code> on an instance field. Usually instance field initializers cannot access <code>this</code> because you don't have access to the new object until all field initializers have completed. But with a <code>late</code> field, that's no longer true, so you <em>can</em> access <code>this</code>, call methods, or access fields on the instance.</p><div class="header-wrapper"><h3 id="late-final-variables">Late final variables</h3><a class="heading-link" href="#late-final-variables" aria-label="Link to 'Late final variables' section">#</a></div><p>You can also combine <code>late</code> with <code>final</code>:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Coffee</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> late</span><span style="color:#D43324"> final</span><span style="color:#0468D7"> String</span><span style="color:#222222"> _temperature;</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> heat</span><span style="color:#222222">() { _temperature = </span><span style="color:#11796D">'hot'</span><span style="color:#222222">; }</span></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> chill</span><span style="color:#222222">() { _temperature = </span><span style="color:#11796D">'iced'</span><span style="color:#222222">; }</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> String</span><span style="color:#6200EE"> serve</span><span style="color:#222222">() => _temperature + </span><span style="color:#11796D">' coffee'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Unlike normal <code>final</code> fields, you do not have to initialize the field in its declaration or in the constructor initialization list. You can assign to it later at runtime. But you can only assign to it <em>once</em>, and that fact is checked at runtime. If you try to assign to it more than once鈥攍ike calling both <code>heat()</code> and <code>chill()</code> here鈥攖he second assignment throws an exception. This is a great way to model state that gets initialized eventually and is immutable afterwards.</p><p>In other words, the new <code>late</code> modifier in combination with Dart's other variable modifiers covers most of the feature space of <code>lateinit</code> in Kotlin and <code>lazy</code> in Swift. You can even use it on local variables if you want a little local lazy evaluation.</p><div class="header-wrapper"><h3 id="required-named-parameters">Required named parameters</h3><a class="heading-link" href="#required-named-parameters" aria-label="Link to 'Required named parameters' section">#</a></div><p>To guarantee that you never see a <code>null</code> parameter with a non-nullable type, the type checker requires all optional parameters to either have a nullable type or a default value. What if you want to have a named parameter with a non-nullable type and no default value? That would imply that you want to require the caller to <em>always</em> pass it. In other words, you want a parameter that is <em>named</em> but not optional.</p><p>I visualize the various kinds of Dart parameters with this table:</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> mandatory optional</span></span> <span class="line"><span> +------------+------------+</span></span> <span class="line"><span>positional | f(int x) | f([int x]) |</span></span> <span class="line"><span> +------------+------------+</span></span> <span class="line"><span>named | ??? | f({int x}) |</span></span> <span class="line"><span> +------------+------------+</span></span></code></pre></div></div><p>For unclear reasons, Dart has long supported three corners of this table but left the combination of named+mandatory empty. With null safety, we filled that in. You declare a required named parameter by placing <code>required</code> before the parameter:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#6200EE">function</span><span style="color:#222222">({</span><span style="color:#0468D7">int</span><span style="color:#222222">? a, </span><span style="color:#D43324">required</span><span style="color:#0468D7"> int</span><span style="color:#222222">? b, </span><span style="color:#0468D7">int</span><span style="color:#222222">? c, </span><span style="color:#D43324">required</span><span style="color:#0468D7"> int</span><span style="color:#222222">? d}) {}</span></span></code></pre></div></div><p>Here, all the parameters must be passed by name. The parameters <code>a</code> and <code>c</code> are optional and can be omitted. The parameters <code>b</code> and <code>d</code> are required and must be passed. Note that required-ness is independent of nullability. You can have required named parameters of nullable types, and optional named parameters of non-nullable types (if they have a default value).</p><p>This is another one of those features that I think makes Dart better regardless of null safety. It simply makes the language feel more complete to me.</p><div class="header-wrapper"><h3 id="abstract-fields">Abstract fields</h3><a class="heading-link" href="#abstract-fields" aria-label="Link to 'Abstract fields' section">#</a></div><p>One of the neat features of Dart is that it upholds a thing called the <a href="https://en.wikipedia.org/wiki/Uniform_access_principle">uniform access principle</a>. In human terms it means that fields are indistinguishable from getters and setters. It's an implementation detail whether a &quot;property&quot; in some Dart class is computed or stored. Because of this, when defining an interface using an abstract class, it's typical to use a field declaration:</p><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">abstract</span><span style="color:#D43324"> class</span><span style="color:#0468D7"> Cup</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#0468D7"> Beverage</span><span style="color:#222222"> contents;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>The intent is that users only implement that class and don't extend it. The field syntax is simply a shorter way of writing a getter/setter pair:</p><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">abstract</span><span style="color:#D43324"> class</span><span style="color:#0468D7"> Cup</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#0468D7"> Beverage</span><span style="color:#D43324"> get</span><span style="color:#222222"> 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">Beverage</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>But Dart doesn't <em>know</em> that this class will never be used as a concrete type. It sees that <code>contents</code> declaration as a real field. And, unfortunately, that field is non-nullable and has no initializer, so you get a compile error.</p><p>One fix is to use explicit abstract getter/setter declarations like in the second example. But that's a little verbose, so with null safety we also added support for explicit abstract field declarations:</p><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">abstract</span><span style="color:#D43324"> class</span><span style="color:#0468D7"> Cup</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> abstract</span><span style="color:#0468D7"> Beverage</span><span style="color:#222222"> contents;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>This behaves exactly like the second example. It simply declares an abstract getter and setter with the given name and type.</p><div class="header-wrapper"><h3 id="working-with-nullable-fields">Working with nullable fields</h3><a class="heading-link" href="#working-with-nullable-fields" aria-label="Link to 'Working with nullable fields' section">#</a></div><p>These new features cover many common patterns and make working with <code>null</code> pretty painless most of the time. But even so, our experience is that nullable fields can still be difficult. In cases where you can make the field <code>late</code> and non-nullable, you're golden. But in many cases you need to <em>check</em> to see if the field has a value, and that requires making it nullable so you can observe the <code>null</code>.</p><p>Nullable fields that are both private and final are able to type promote (barring <a href="/tools/non-promotion-reasons">some particular reasons</a>). If you can't make a field private and final for whatever reason, you'll still need a workaround.</p><p>For example, you might expect this to work:</p><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:#6E6E70">// Using null safety, incorrectly:</span></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Coffee</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#0468D7"> String</span><span style="color:#222222">? _temperature;</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> heat</span><span style="color:#222222">() { _temperature = </span><span style="color:#11796D">'hot'</span><span style="color:#222222">; }</span></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> chill</span><span style="color:#222222">() { _temperature = </span><span style="color:#11796D">'iced'</span><span style="color:#222222">; }</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> checkTemp</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (_temperature != </span><span style="color:#11796D">null</span><span style="color:#222222">) {</span></span> <span class="line"><span style="color:#6200EE"> print</span><span style="color:#222222">(</span><span style="color:#11796D">'Ready to serve '</span><span style="color:#222222"> + _temperature + </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:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> String</span><span style="color:#6200EE"> serve</span><span style="color:#222222">() => _temperature! + </span><span style="color:#11796D">' coffee'</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Inside <code>checkTemp()</code>, we check to see if <code>_temperature</code> is <code>null</code>. If not, we access it and end up calling <code>+</code> on it. Unfortunately, this is not allowed.</p><p>Flow-based type promotion can only apply to fields that are <em>both private and final</em>. Otherwise, static analysis cannot <em>prove</em> that the field's value doesn't change between the point that you check for <code>null</code> and the point that you use it. (Consider that in pathological cases, the field itself could be overridden by a getter in a subclass that returns <code>null</code> the second time it is called.)</p><p>So, since we care about soundness, public and/or non-final fields don't promote, and the above method does not compile. This is annoying. In simple cases like here, your best bet is to slap a <code>!</code> on the use of the field. It seems redundant, but that's more or less how Dart behaves today.</p><p>Another pattern that helps is to copy the field to a local variable first and then use that instead:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> checkTemp</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#D43324"> var</span><span style="color:#222222"> temperature = _temperature;</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (temperature != </span><span style="color:#11796D">null</span><span style="color:#222222">) {</span></span> <span class="line"><span style="color:#6200EE"> print</span><span style="color:#222222">(</span><span style="color:#11796D">'Ready to serve '</span><span style="color:#222222"> + temperature + </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:#222222">}</span></span></code></pre></div></div><p>Since the type promotion does apply to locals, this now works fine. If you need to <em>change</em> the value, just remember to store back to the field and not just the local.</p><p>For more information on handling these and other type promotion issues, see <a href="/tools/non-promotion-reasons">Fixing type promotion failures</a>.</p><div class="header-wrapper"><h3 id="nullability-and-generics">Nullability and generics</h3><a class="heading-link" href="#nullability-and-generics" aria-label="Link to 'Nullability and generics' section">#</a></div><p>Like most modern statically-typed languages, Dart has generic classes and generic methods. They interact with nullability in a few ways that seem counter-intuitive but make sense once you think through the implications. First is that &quot;is this type nullable?&quot; is no longer a simple yes or no question. Consider:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Box</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">T</span><span style="color:#222222">> {</span></span> <span class="line"><span style="color:#D43324"> final</span><span style="color:#0468D7"> T</span><span style="color:#222222"> object;</span></span> <span class="line"><span style="color:#0468D7"> Box</span><span style="color:#222222">(</span><span style="color:#D43324">this</span><span style="color:#222222">.object);</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"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#0468D7"> Box</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">String</span><span style="color:#222222">>(</span><span style="color:#11796D">'a string'</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#0468D7"> Box</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">int</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></code></pre></div></div><p>In the definition of <code>Box</code>, is <code>T</code> a nullable type or a non-nullable type? As you can see, it can be instantiated with either kind. The answer is that <code>T</code> is a <em>potentially nullable type</em>. Inside the body of a generic class or method, a potentially nullable type has all of the restrictions of both nullable types <em>and</em> non-nullable types.</p><p>The former means you can't call any methods on it except the handful defined on Object. The latter means that you must initialize any fields or variables of that type before they're used. This can make type parameters pretty hard to work with.</p><p>In practice, a few patterns show up. In collection-like classes where the type parameter can be instantiated with any type at all, you just have to deal with the restrictions. In most cases, like the example here, it means ensuring you do have access to a value of the type argument's type whenever you need to work with one. Fortunately, collection-like classes rarely call methods on their elements.</p><p>In places where you don't have access to a value, you can make the use of the type parameter nullable:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Box</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">T</span><span style="color:#222222">> {</span></span> <span class="line"><span style="color:#0468D7"> T</span><span style="color:#222222">? object;</span></span> <span class="line"><span style="color:#0468D7"> Box</span><span style="color:#222222">.</span><span style="color:#6200EE">empty</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#0468D7"> Box</span><span style="color:#222222">.</span><span style="color:#6200EE">full</span><span style="color:#222222">(</span><span style="color:#D43324">this</span><span style="color:#222222">.object);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Note the <code>?</code> on the declaration of <code>object</code>. Now the field has an explicitly nullable type, so it is fine to leave it uninitialized.</p><p>When you make a type parameter type nullable like <code>T?</code> here, you may need to cast the nullability away. The correct way to do that is using an explicit <code>as T</code> cast, <em>not</em> the <code>!</code> operator:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Box</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">T</span><span style="color:#222222">> {</span></span> <span class="line"><span style="color:#0468D7"> T</span><span style="color:#222222">? object;</span></span> <span class="line"><span style="color:#0468D7"> Box</span><span style="color:#222222">.</span><span style="color:#6200EE">empty</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#0468D7"> Box</span><span style="color:#222222">.</span><span style="color:#6200EE">full</span><span style="color:#222222">(</span><span style="color:#D43324">this</span><span style="color:#222222">.object);</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> T</span><span style="color:#6200EE"> unbox</span><span style="color:#222222">() => object </span><span style="color:#D43324">as</span><span style="color:#0468D7"> T</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>The <code>!</code> operator <em>always</em> throws if the value is <code>null</code>. But if the type parameter has been instantiated with a nullable type, then <code>null</code> is a perfectly valid value for <code>T</code>:</p><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:#6E6E70">// Using null safety:</span></span> <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"> box = </span><span style="color:#0468D7">Box</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">int</span><span style="color:#222222">?>.</span><span style="color:#6200EE">full</span><span style="color:#222222">(</span><span style="color:#11796D">null</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#6200EE"> print</span><span style="color:#222222">(box.</span><span style="color:#6200EE">unbox</span><span style="color:#222222">());</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>This program should run without error. Using <code>as T</code> accomplishes that. Using <code>!</code> would throw an exception.</p><p>Other generic types have some bound that restricts the kinds of type arguments that can be applied:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Interval</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">T</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> num</span><span style="color:#222222">> {</span></span> <span class="line"><span style="color:#0468D7"> T</span><span style="color:#222222"> min, max;</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> Interval</span><span style="color:#222222">(</span><span style="color:#D43324">this</span><span style="color:#222222">.min, </span><span style="color:#D43324">this</span><span style="color:#222222">.max);</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> bool</span><span style="color:#D43324"> get</span><span style="color:#222222"> isEmpty => max &#x3C;= min;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>If the bound is non-nullable, then the type parameter is also non-nullable. This means you have the restrictions of non-nullable types鈥攜ou can't leave fields and variables uninitialized. The example class here must have a constructor that initializes the fields.</p><p>In return for that restriction, you can call any methods on values of the type parameter type that are declared on its bound. Having a non-nullable bound does, however, prevent <em>users</em> of your generic class from instantiating it with a nullable type argument. That's probably a reasonable limitation for most classes.</p><p>You can also use a nullable <em>bound</em>:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Interval</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">T</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> num</span><span style="color:#222222">?> {</span></span> <span class="line"><span style="color:#0468D7"> T</span><span style="color:#222222"> min, max;</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> Interval</span><span style="color:#222222">(</span><span style="color:#D43324">this</span><span style="color:#222222">.min, </span><span style="color:#D43324">this</span><span style="color:#222222">.max);</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7"> bool</span><span style="color:#D43324"> get</span><span style="color:#222222"> isEmpty {</span></span> <span class="line"><span style="color:#D43324"> var</span><span style="color:#222222"> localMin = min;</span></span> <span class="line"><span style="color:#D43324"> var</span><span style="color:#222222"> localMax = max;</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70"> // No min or max means an open-ended interval.</span></span> <span class="line"><span style="color:#D43324"> if</span><span style="color:#222222"> (localMin == </span><span style="color:#11796D">null</span><span style="color:#222222"> || localMax == </span><span style="color:#11796D">null</span><span style="color:#222222">) </span><span style="color:#D43324">return</span><span style="color:#11796D"> false</span><span style="color:#222222">;</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> localMax &#x3C;= localMin;</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>This means that in the body of the class you get the flexibility of treating the type parameter as nullable, but you also have the limitations of nullability. You can't call anything on a variable of that type unless you deal with the nullability first. In the example here, we copy the fields in local variables and check those locals for <code>null</code> so that flow analysis promotes them to non-nullable types before we use <code>&lt;=</code>.</p><p>Note that a nullable bound does not prevent users from instantiating the class with non-nullable types. A nullable bound means that the type argument <em>can</em> be nullable, not that it <em>must</em>. (In fact, the default bound on type parameters if you don't write an <code>extends</code> clause is the nullable bound <code>Object?</code>.) There is no way to <em>require</em> a nullable type argument. If you want uses of the type parameter to reliably be nullable and be implicitly initialized to <code>null</code>, you can use <code>T?</code> inside the body of the class.</p><div class="header-wrapper"><h2 id="core-library-changes">Core library changes</h2><a class="heading-link" href="#core-library-changes" aria-label="Link to 'Core library changes' section">#</a></div><p>There are a couple of other tweaks here and there in the language, but they are minor. Things like the default type of a <code>catch</code> with no <code>on</code> clause is now <code>Object</code> instead of <code>dynamic</code>. Fallthrough analysis in switch statements uses the new flow analysis.</p><p>The remaining changes that really matter to you are in the core libraries. Before we embarked on the Grand Null Safety Adventure, we worried that it would turn out there was no way to make our core libraries null safe without massively breaking the world. It turned out not so dire. There <em>are</em> a few significant changes, but for the most part, the migration went smoothly. Most core libraries either did not accept <code>null</code> and naturally move to non-nullable types, or do and gracefully accept it with a nullable type.</p><p>There are a few important corners, though:</p><div class="header-wrapper"><h3 id="the-map-index-operator-is-nullable">The Map index operator is nullable</h3><a class="heading-link" href="#the-map-index-operator-is-nullable" aria-label="Link to 'The Map index operator is nullable' section">#</a></div><p>This isn't really a change, but more a thing to know. The index <code>[]</code> operator on the Map class returns <code>null</code> if the key isn't present. This implies that the return type of that operator must be nullable: <code>V?</code> instead of <code>V</code>.</p><p>We could have changed that method to throw an exception when the key isn't present and then given it an easier-to-use non-nullable return type. But code that uses the index operator and checks for <code>null</code> to see if the key is absent is very common, around half of all uses based on our analysis. Breaking all of that code would have set the Dart ecosystem aflame.</p><p>Instead, the runtime behavior is the same and thus the return type is obliged to be nullable. This means you generally cannot immediately use the result of a map lookup:</p><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:#6E6E70">// Using null safety, incorrectly:</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> map = {</span><span style="color:#11796D">'key'</span><span style="color:#222222">: </span><span style="color:#11796D">'value'</span><span style="color:#222222">};</span></span> <span class="line"><span style="color:#6200EE">print</span><span style="color:#222222">(map[</span><span style="color:#11796D">'key'</span><span style="color:#222222">].length); </span><span style="color:#6E6E70">// Error.</span></span></code></pre></div></div><p>This gives you a compile error on the attempt to call <code>.length</code> on a nullable string. In cases where you <em>know</em> the key is present you can teach the type checker by using <code>!</code>:</p><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:#6E6E70">// Using null safety:</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> map = {</span><span style="color:#11796D">'key'</span><span style="color:#222222">: </span><span style="color:#11796D">'value'</span><span style="color:#222222">};</span></span> <span class="line"><span style="color:#6200EE">print</span><span style="color:#222222">(map[</span><span style="color:#11796D">'key'</span><span style="color:#222222">]!.length); </span><span style="color:#6E6E70">// OK.</span></span></code></pre></div></div><p>We considered adding another method to Map that would do this for you: look up the key, throw if not found, or return a non-nullable value otherwise. But what to call it? No name would be shorter than the single-character <code>!</code>, and no method name would be clearer than seeing a <code>!</code> with its built-in semantics right there at the call site. So the idiomatic way to access a known-present element in a map is to use <code>[]!</code>. You get used to it.</p><div class="header-wrapper"><h3 id="no-unnamed-list-constructor">No unnamed List constructor</h3><a class="heading-link" href="#no-unnamed-list-constructor" aria-label="Link to 'No unnamed List constructor' section">#</a></div><p>The unnamed constructor on <code>List</code> creates a new list with the given size but does not initialize any of the elements. This would poke a very large hole in the soundness guarantees if you created a list of a non-nullable type and then accessed an element.</p><p>To avoid that, we have removed the constructor entirely. It is an error to call <code>List()</code> in null-safe code, even with a nullable type. That sounds scary, but in practice most code creates lists using list literals, <code>List.filled()</code>, <code>List.generate()</code>, or as a result of transforming some other collection. For the edge case where you want to create an empty list of some type, we added a new <code>List.empty()</code> constructor.</p><p>The pattern of creating a completely uninitialized list has always felt out of place in Dart, and now it is even more so. If you have code broken by this, you can always fix it by using one of the many other ways to produce a list.</p><div class="header-wrapper"><h3 id="cannot-set-a-larger-length-on-non-nullable-lists">Cannot set a larger length on non-nullable lists</h3><a class="heading-link" href="#cannot-set-a-larger-length-on-non-nullable-lists" aria-label="Link to 'Cannot set a larger length on non-nullable lists' section">#</a></div><p>This is little known, but the <code>length</code> getter on <code>List</code> also has a corresponding <em>setter</em>. You can set the length to a shorter value to truncate the list. And you can also set it to a <em>longer</em> length to pad the list with uninitialized elements.</p><p>If you were to do that with a list of a non-nullable type, you'd violate soundness when you later accessed those unwritten elements. To prevent that, the <code>length</code> setter will throw a runtime exception if (and only if) the list has a non-nullable element type <em>and</em> you set it to a <em>longer</em> length. It is still fine to truncate lists of all types, and you can grow lists of nullable types.</p><p>There is an important consequence of this if you define your own list types that extend <code>ListBase</code> or apply <code>ListMixin</code>. Both of those types provide an implementation of <code>insert()</code> that previously made room for the inserted element by setting the length. That would fail with null safety, so instead we changed the implementation of <code>insert()</code> in <code>ListMixin</code> (which <code>ListBase</code> shares) to call <code>add()</code> instead. Your custom list class should provide a definition of <code>add()</code> if you want to be able to use that inherited <code>insert()</code> method.</p><div class="header-wrapper"><h3 id="cannot-access-iterator-current-before-or-after-iteration">Cannot access Iterator.current before or after iteration</h3><a class="heading-link" href="#cannot-access-iterator-current-before-or-after-iteration" aria-label="Link to 'Cannot access Iterator.current before or after iteration' section">#</a></div><p>The <code>Iterator</code> class is the mutable &quot;cursor&quot; class used to traverse the elements of a type that implements <code>Iterable</code>. You are expected to call <code>moveNext()</code> before accessing any elements to advance to the first element. When that method returns <code>false</code>, you have reached the end and there are no more elements.</p><p>It used to be that <code>current</code> returned <code>null</code> if you called it either before calling <code>moveNext()</code> the first time or after iteration finished. With null safety, that would require the return type of <code>current</code> to be <code>E?</code> and not <code>E</code>. That in turn means every element access would require a runtime <code>null</code> check.</p><p>Those checks would be useless given that almost no one ever accesses the current element in that erroneous way. Instead, we have made the type of <code>current</code> be <code>E</code>. Since there <em>may</em> be a value of that type available before or after iterating, we've left the iterator's behavior undefined if you call it when you aren't supposed to. Most implementations of <code>Iterator</code> throw a <code>StateError</code>.</p><div class="header-wrapper"><h2 id="summary">Summary</h2><a class="heading-link" href="#summary" aria-label="Link to 'Summary' section">#</a></div><p>That is a very detailed tour through all of the language and library changes around null safety. It's a lot of stuff, but this is a pretty big language change. More importantly, we wanted to get to a point where Dart still feels cohesive and usable. That requires changing not just the type system, but a number of other usability features around it. We didn't want it to feel like null safety was bolted on.</p><p>The core points to take away are:</p><ul><li><p>Types are non-nullable by default and made nullable by adding <code>?</code>.</p></li><li><p>Optional parameters must be nullable or have a default value. You can use <code>required</code> to make named parameters non-optional. Non-nullable top-level variables and static fields must have initializers. Non-nullable instance fields must be initialized before the constructor body begins.</p></li><li><p>Method chains after null-aware operators short circuit if the receiver is <code>null</code>. There are new null-aware cascade (<code>?..</code>) and index (<code>?[]</code>) operators. The postfix null assertion &quot;bang&quot; operator (<code>!</code>) casts its nullable operand to the underlying non-nullable type.</p></li><li><p>Flow analysis lets you safely turn nullable local variables and parameters (and private final fields, as of Dart 3.2) into usable non-nullable ones. The new flow analysis also has smarter rules for type promotion, missing returns, unreachable code, and variable initialization.</p></li><li><p>The <code>late</code> modifier lets you use non-nullable types and <code>final</code> in places you otherwise might not be able to, at the expense of runtime checking. It also gives you lazy-initialized fields.</p></li><li><p>The <code>List</code> class is changed to prevent uninitialized elements.</p></li></ul><p>Finally, once you absorb all of that and get your code into the world of null safety, you get a sound program that the compilers can optimize and where every place a runtime error can occur is visible in your code. We hope you feel that's worth the effort to get there.</p><p id="page-github-links"><span>Unless stated otherwise, the documentation on this site reflects Dart 3.5.4. Page last updated on 2024-05-14.</span> <a href="https://github.com/dart-lang/site-www/tree/main/src/content/null-safety/understanding-null-safety.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/null-safety/understanding-null-safety/&page-source=https://github.com/dart-lang/site-www/tree/main/src/content/null-safety/understanding-null-safety.md" title="Report an issue with this page" target="_blank" rel="noopener">report an issue</a>.</p></div></article></main><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="Medium blog"><svg><use href="/assets/img/social/medium.svg#medium"></use></svg> </a><a href="https://github.com/dart-lang" target="_blank" rel="noopener" title="GitHub"><svg><use href="/assets/img/social/github.svg#github"></use></svg> </a><a href="https://twitter.com/dart_lang" target="_blank" rel="noopener" title="X (Twitter)"><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></body></html>

Pages: 1 2 3 4 5 6 7 8 9 10