CINXE.COM
Class modifiers for API maintainers | 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="How to use the class modifiers added in Dart 3.0 to make your package's API more robust and maintainable."><title>Class modifiers for API maintainers | 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="Class modifiers for API maintainers"><meta name="twitter:description" content="How to use the class modifiers added in Dart 3.0 to make your package's API more robust and maintainable."><meta property="og:title" content="Class modifiers for API maintainers"><meta property="og:description" content="How to use the class modifiers added in Dart 3.0 to make your package's API more robust and maintainable."><meta property="og:url" content="/language/class-modifiers-for-apis/"><meta property="og:image" content="/assets/img/logo/dart-logo-for-shares.png?2" eleventy:ignore><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;500;700&display=swap" rel="stylesheet"><link href="https://fonts.googleapis.com/css2?family=Google+Sans+Display:wght@400&display=swap" rel="stylesheet"><link href="https://fonts.googleapis.com/css2?family=Google+Sans+Mono:wght@400;500;700&display=swap" rel="stylesheet"><link href="https://fonts.googleapis.com/css2?family=Google+Sans+Text:wght@400;500;700&display=swap" rel="stylesheet"><link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0..1,0" rel="stylesheet"><link rel="stylesheet" href="/assets/css/main.css?v=3"><script src="/assets/js/os-tabs.js?v=3"></script><script src="/assets/js/main.js?v=3"></script><script>!function(e,a,t,n,c,o,s){e.GoogleAnalyticsObject=c,e[c]=e[c]||function(){(e[c].q=e[c].q||[]).push(arguments)},e[c].l=1*new Date,o=a.createElement(t),s=a.getElementsByTagName(t)[0],o.async=1,o.src="//www.google-analytics.com/analytics.js",s.parentNode.insertBefore(o,s)}(window,document,"script",0,"ga"),ga("create","UA-26406144-4","auto"),ga("send","pageview")</script></head><body class="default.html"><a id="skip-to-main" class="filled-button" href="#site-content-title" tabindex="1">Skip to main content</a><section id="cookie-notice"><div class="container"><p>dart.dev uses cookies from Google to deliver and enhance the quality of its services and to analyze traffic.</p><div class="button-group"><a class="text-button" href="https://policies.google.com/technologies/cookies" target="_blank" rel="noopener">Learn more</a> <button id="cookie-consent" class="filled-button">OK, got it</button></div></div></section><noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-5VSZM5J" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript><div id="site-banner" role="alert"><p>Announcing Dart 3.7! Find out about updates to the language, analyzer, pub.dev, and more, in the <a href="https://medium.com/dartlang/announcing-dart-3-7-bf864a1b195c" target="_blank">blog post</a>.</p></div><header id="site-header"><nav id="mainnav"><div id="menu-toggle"><span class="material-symbols" title="Toggle side navigation menu." aria-label="Toggle side navigation menu." type="button">menu</span></div><a href="/" class="brand" title="Dart"><img src="/assets/img/logo/logo-white-text.svg" alt="Dart"></a><ul class="navbar"><li><a href="/overview" class="nav-link">Overview</a></li><li class="mainnav__get-started"><a href="/docs" class="nav-link active"><span>Docs</span></a></li><li><a href="/community" class="nav-link">Community</a></li><li><a href="/#try-dart" class="nav-link">Try Dart</a></li><li><a href="/get-dart" class="nav-link">Get Dart</a></li><li class="searchfield"><form action="/search" class="site-header-search form-inline" id="cse-search-box"><input type="hidden" name="cx" value="011220921317074318178:_yy-tmb5t_i"> <input type="hidden" name="ie" value="UTF-8"> <input type="hidden" name="hl" value="en"> <input class="site-header-searchfield form-control search-field" type="search" name="q" id="search-main" autocomplete="off" placeholder="Search" aria-label="Search"></form></li></ul></nav></header><div id="site-below-header"><div id="site-main-row"><div id="sidenav"><form action="/search/" class="site-header-search form-inline"><input class="site-header-searchfield form-control search-field" type="search" name="q" id="search-side" autocomplete="off" placeholder="Search" aria-label="Search"></form><ul class="navbar-nav"><li aria-hidden="true"><div class="sidenav-divider"></div></li><li class="nav-item"><a href="/overview" class="nav-link">Overview</a></li><li class="nav-item"><a href="/community" class="nav-link">Community</a></li><li class="nav-item"><a href="https://dartpad.dev" class="nav-link">Try Dart</a></li><li class="nav-item"><a href="/get-dart" class="nav-link">Get Dart</a></li><li class="nav-item"><a href="/docs" class="nav-link">Docs</a></li><li aria-hidden="true"><div class="sidenav-divider"></div></li></ul><ul class="nav"><li class="nav-item"><button class="nav-link active collapsible" data-toggle="collapse" data-target="#-sidenav-1" role="button" aria-expanded="true" aria-controls="-sidenav-1"><span>Language</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse show" id="-sidenav-1"><li class="nav-item"><a class="nav-link" href="/language"><div><span>Introduction</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-1-2" role="button" aria-expanded="false" aria-controls="-sidenav-1-2"><span>Syntax basics</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-1-2"><li class="nav-item"><a class="nav-link" href="/language/variables"><div><span>Variables</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/operators"><div><span>Operators</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/comments"><div><span>Comments</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/metadata"><div><span>Metadata</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/libraries"><div><span>Libraries & imports</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/keywords"><div><span>Keywords</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-1-3" role="button" aria-expanded="false" aria-controls="-sidenav-1-3"><span>Types</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-1-3"><li class="nav-item"><a class="nav-link" href="/language/built-in-types"><div><span>Built-in types</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/records"><div><span>Records</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/collections"><div><span>Collections</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/generics"><div><span>Generics</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/typedefs"><div><span>Typedefs</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/type-system"><div><span>Type system</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-1-4" role="button" aria-expanded="false" aria-controls="-sidenav-1-4"><span>Patterns</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-1-4"><li class="nav-item"><a class="nav-link" href="/language/patterns"><div><span>Overview & usage</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/pattern-types"><div><span>Pattern types</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records" target="_blank" rel="noopener"><div><span>Applied tutorial</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li></ul></li><li class="nav-item"><a class="nav-link" href="/language/functions"><div><span>Functions</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-1-6" role="button" aria-expanded="false" aria-controls="-sidenav-1-6"><span>Control flow</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-1-6"><li class="nav-item"><a class="nav-link" href="/language/loops"><div><span>Loops</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/branches"><div><span>Branches</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/error-handling"><div><span>Error handling</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-1-7" role="button" aria-expanded="false" aria-controls="-sidenav-1-7"><span>Classes & objects</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-1-7"><li class="nav-item"><a class="nav-link" href="/language/classes"><div><span>Classes</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/constructors"><div><span>Constructors</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/methods"><div><span>Methods</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/extend"><div><span>Extend a class</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/mixins"><div><span>Mixins</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/enums"><div><span>Enums</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/extension-methods"><div><span>Extension methods</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/extension-types"><div><span>Extension types</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/callable-objects"><div><span>Callable objects</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link active collapsible" data-toggle="collapse" data-target="#-sidenav-1-8" role="button" aria-expanded="true" aria-controls="-sidenav-1-8"><span>Class modifiers</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse show" id="-sidenav-1-8"><li class="nav-item"><a class="nav-link" href="/language/class-modifiers"><div><span>Overview & usage</span></div></a></li><li class="nav-item"><a class="nav-link active" href="/language/class-modifiers-for-apis"><div><span>Class modifiers for API maintainers</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/modifier-reference"><div><span>Reference</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-1-9" role="button" aria-expanded="false" aria-controls="-sidenav-1-9"><span>Concurrency</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-1-9"><li class="nav-item"><a class="nav-link" href="/language/concurrency"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/async"><div><span>Asynchronous support</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/isolates"><div><span>Isolates</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-1-10" role="button" aria-expanded="false" aria-controls="-sidenav-1-10"><span>Null safety</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-1-10"><li class="nav-item"><a class="nav-link" href="/null-safety"><div><span>Sound null safety</span></div></a></li><li class="nav-item"><a class="nav-link" href="/null-safety/migration-guide"><div><span>Migrating to null safety</span></div></a></li><li class="nav-item"><a class="nav-link" href="/null-safety/understanding-null-safety"><div><span>Understanding null safety</span></div></a></li><li class="nav-item"><a class="nav-link" href="/null-safety/unsound-null-safety"><div><span>Unsound null safety</span></div></a></li><li class="nav-item"><a class="nav-link" href="/null-safety/faq"><div><span>FAQ</span></div></a></li></ul></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#-sidenav-2" role="button" aria-expanded="false" aria-controls="-sidenav-2"><span>Core libraries</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-2"><li class="nav-item"><a class="nav-link" href="/libraries"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/dart-core"><div><span>dart:core</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/dart-async"><div><span>dart:async</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/dart-math"><div><span>dart:math</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/dart-convert"><div><span>dart:convert</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/dart-io"><div><span>dart:io</span></div></a></li><li class="nav-item"><a class="nav-link" href="/interop/js-interop"><div><span>dart:js_interop</span></div></a></li><div class="sidenav-divider"></div><li class="nav-item"><a class="nav-link" href="/libraries/collections/iterables"><div><span>Iterable collections</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-2-10" role="button" aria-expanded="false" aria-controls="-sidenav-2-10"><span>Asynchronous programming</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-2-10"><li class="nav-item"><a class="nav-link" href="/libraries/async/async-await"><div><span>Tutorial</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/async/futures-error-handling"><div><span>Futures and error handling</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/async/using-streams"><div><span>Using streams</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/async/creating-streams"><div><span>Creating streams</span></div></a></li></ul></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#-sidenav-3" role="button" aria-expanded="false" aria-controls="-sidenav-3"><span>Effective Dart</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-3"><li class="nav-item"><a class="nav-link" href="/effective-dart"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/effective-dart/style"><div><span>Style</span></div></a></li><li class="nav-item"><a class="nav-link" href="/effective-dart/documentation"><div><span>Documentation</span></div></a></li><li class="nav-item"><a class="nav-link" href="/effective-dart/usage"><div><span>Usage</span></div></a></li><li class="nav-item"><a class="nav-link" href="/effective-dart/design"><div><span>Design</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#-sidenav-4" role="button" aria-expanded="false" aria-controls="-sidenav-4"><span>Packages</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-4"><li class="nav-item"><a class="nav-link" href="/tools/pub/packages"><div><span>How to use packages</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/useful-packages"><div><span>Commonly used packages</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/create-packages"><div><span>Creating packages</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/publishing"><div><span>Publishing packages</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/writing-package-pages"><div><span>Writing package pages</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/workspaces"><div><span>Workspaces (monorepo support)</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-4-7" role="button" aria-expanded="false" aria-controls="-sidenav-4-7"><span>Package reference</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-4-7"><li class="nav-item"><a class="nav-link" href="/tools/pub/dependencies"><div><span>Dependencies</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/glossary"><div><span>Glossary</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/package-layout"><div><span>Package layout conventions</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/environment-variables"><div><span>Pub environment variables</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/pubspec"><div><span>Pubspec file</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/troubleshoot"><div><span>Troubleshooting pub</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/verified-publishers"><div><span>Verified publishers</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/security-advisories"><div><span>Security advisories</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/versioning"><div><span>Versioning</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/custom-package-repositories"><div><span>Custom package repositories</span></div></a></li></ul></li><li class="nav-item"><a class="nav-link" href="/tools/pub/private-files"><div><span>What not to commit</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#-sidenav-5" role="button" aria-expanded="false" aria-controls="-sidenav-5"><span>Development</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-5"><li class="nav-item"><a class="nav-link" href="/libraries/serialization/json"><div><span>JSON serialization</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/language/number-representation"><div><span>Number representation</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/google-apis"><div><span>Google APIs</span></div></a></li><li class="nav-item"><a class="nav-link" href="/multiplatform-apps"><div><span>Multi-platform apps</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-5-5" role="button" aria-expanded="false" aria-controls="-sidenav-5-5"><span>Command-line & server apps</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-5-5"><li class="nav-item"><a class="nav-link" href="/server"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tutorials/server/get-started"><div><span>Get started</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tutorials/server/cmdline"><div><span>Write command-line apps</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tutorials/server/fetch-data"><div><span>Fetch data from the internet</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tutorials/server/httpserver"><div><span>Write HTTP servers</span></div></a></li><li class="nav-item"><a class="nav-link" href="/server/libraries"><div><span>Libraries & packages</span></div></a></li><li class="nav-item"><a class="nav-link" href="/server/google-cloud"><div><span>Google Cloud</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-5-6" role="button" aria-expanded="false" aria-controls="-sidenav-5-6"><span>Web apps</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-5-6"><li class="nav-item"><a class="nav-link" href="/web"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/web/get-started"><div><span>Get started</span></div></a></li><li class="nav-item"><a class="nav-link" href="/web/deployment"><div><span>Deployment</span></div></a></li><li class="nav-item"><a class="nav-link" href="/web/libraries"><div><span>Libraries & packages</span></div></a></li><li class="nav-item"><a class="nav-link" href="/web/wasm"><div><span>Wasm compilation</span></div></a></li></ul></li><li class="nav-item"><a class="nav-link" href="/libraries/core/environment-declarations"><div><span>Environment declarations</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#-sidenav-6" role="button" aria-expanded="false" aria-controls="-sidenav-6"><span>Interoperability</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-6"><li class="nav-item"><a class="nav-link" href="/interop/c-interop"><div><span>C interop</span></div></a></li><li class="nav-item"><a class="nav-link" href="/interop/objective-c-interop"><div><span>Objective-C & Swift interop</span></div></a></li><li class="nav-item"><a class="nav-link" href="/interop/java-interop"><div><span>Java & Kotlin interop</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-6-4" role="button" aria-expanded="false" aria-controls="-sidenav-6-4"><span>JavaScript interop</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-6-4"><li class="nav-item"><a class="nav-link" href="/interop/js-interop"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/interop/js-interop/usage"><div><span>Usage</span></div></a></li><li class="nav-item"><a class="nav-link" href="/interop/js-interop/js-types"><div><span>JS types</span></div></a></li><li class="nav-item"><a class="nav-link" href="/interop/js-interop/tutorials"><div><span>Tutorials</span></div></a></li><li class="nav-item"><a class="nav-link" href="/interop/js-interop/past-js-interop"><div><span>Past JS interop</span></div></a></li><div class="sidenav-divider"></div><li class="nav-item"><a class="nav-link" href="/interop/js-interop/package-web"><div><span>Web interop</span></div></a></li></ul></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#-sidenav-7" role="button" aria-expanded="false" aria-controls="-sidenav-7"><span>Tools & techniques</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-7"><li class="nav-item"><a class="nav-link" href="/tools"><div><span>Overview</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-7-2" role="button" aria-expanded="false" aria-controls="-sidenav-7-2"><span>Editors & debuggers</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-7-2"><li class="nav-item"><a class="nav-link" href="/tools/jetbrains-plugin"><div><span>IntelliJ & Android Studio</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/vs-code"><div><span>VS Code</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-devtools"><div><span>Dart DevTools</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-7-2-4" role="button" aria-expanded="false" aria-controls="-sidenav-7-2-4"><span>DartPad</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-7-2-4"><li class="nav-item"><a class="nav-link" href="/tools/dartpad"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dartpad/troubleshoot"><div><span>Troubleshooting DartPad</span></div></a></li></ul></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-7-3" role="button" aria-expanded="false" aria-controls="-sidenav-7-3"><span>Command-line tools</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-7-3"><li class="nav-item"><button class="nav-link collapsible" data-toggle="collapse" data-target="#-sidenav-7-3-1" role="button" aria-expanded="true" aria-controls="-sidenav-7-3-1"><span>Dart SDK</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse show" id="-sidenav-7-3-1"><li class="nav-item"><a class="nav-link" href="/tools/sdk"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-tool"><div><span>dart</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-analyze"><div><span>dart analyze</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-compile"><div><span>dart compile</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-create"><div><span>dart create</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-doc"><div><span>dart doc</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-fix"><div><span>dart fix</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-format"><div><span>dart format</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-info"><div><span>dart info</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/cmd"><div><span>dart pub</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-run"><div><span>dart run</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-test"><div><span>dart test</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dartaotruntime"><div><span>dartaotruntime</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/experiment-flags"><div><span>Experiment flags</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible" data-toggle="collapse" data-target="#-sidenav-7-3-2" role="button" aria-expanded="true" aria-controls="-sidenav-7-3-2"><span>Other command-line tools</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse show" id="-sidenav-7-3-2"><li class="nav-item"><a class="nav-link" href="/tools/build_runner"><div><span>build_runner</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/webdev"><div><span>webdev</span></div></a></li></ul></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-7-4" role="button" aria-expanded="false" aria-controls="-sidenav-7-4"><span>Static analysis</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-7-4"><li class="nav-item"><a class="nav-link" href="/tools/analysis"><div><span>Customizing static analysis</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/non-promotion-reasons"><div><span>Fixing type promotion failures</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/linter-rules"><div><span>Linter rules</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/diagnostic-messages"><div><span>Diagnostic messages</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-7-5" role="button" aria-expanded="false" aria-controls="-sidenav-7-5"><span>Testing & optimization</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-7-5"><li class="nav-item"><a class="nav-link" href="/tools/testing"><div><span>Testing</span></div></a></li><li class="nav-item"><a class="nav-link" href="/web/debugging"><div><span>Debugging web apps</span></div></a></li></ul></li></ul></li><li aria-hidden="true"><div class="sidenav-divider"></div></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#-sidenav-9" role="button" aria-expanded="false" aria-controls="-sidenav-9"><span>Resources</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-9"><li class="nav-item"><a class="nav-link" href="/resources/dart-cheatsheet"><div><span>Language cheatsheet</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/breaking-changes"><div><span>Breaking changes</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/language/evolution"><div><span>Language evolution</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/language/spec"><div><span>Language specification</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/dart-3-migration"><div><span>Dart 3 migration guide</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-9-6" role="button" aria-expanded="false" aria-controls="-sidenav-9-6"><span>Coming from ...</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-9-6"><li class="nav-item"><a class="nav-link" href="/resources/coming-from/js-to-dart"><div><span>JavaScript to Dart</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/coming-from/swift-to-dart"><div><span>Swift to Dart</span></div></a></li></ul></li><div class="sidenav-divider"></div><li class="nav-item"><a class="nav-link" href="/resources/faq"><div><span>FAQ</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/glossary"><div><span>Glossary</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/books"><div><span>Books</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/videos"><div><span>Videos</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tutorials"><div><span>Tutorials</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible" data-toggle="collapse" data-target="#-sidenav-10" role="button" aria-expanded="true" aria-controls="-sidenav-10"><span>Related sites</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse show" id="-sidenav-10"><li class="nav-item"><a class="nav-link" href="https://api.dart.dev" target="_blank" rel="noopener"><div><span>API reference</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://medium.com/dartlang" target="_blank" rel="noopener"><div><span>Blog</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://dartpad.dev" target="_blank" rel="noopener"><div><span>DartPad (online editor)</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://flutter.dev" target="_blank" rel="noopener"><div><span>Flutter</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://pub.dev" target="_blank" rel="noopener"><div><span>Package site</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li></ul></li></ul></div><main id="page-content"><div id="site-toc--side" class="site-toc"><header class="site-toc__title">Contents</header><ul class="section-nav"><li class="toc-entry nav-item"><a class="nav-link" href="#the-mixin-modifier-on-classes">The mixin modifier on classes</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#migrating-classes-as-mixins">Migrating classes as mixins</a></li></ul></li><li class="toc-entry nav-item"><a class="nav-link" href="#other-opt-in-modifiers">Other opt-in modifiers</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#the-interface-modifier">The interface modifier</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#the-base-modifier">The base modifier</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#base-transitivity">Base transitivity</a></li></ul></li><li class="toc-entry nav-item"><a class="nav-link" href="#the-final-modifier">The final modifier</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#the-sealed-modifier">The sealed modifier</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#sealed-versus-final">sealed versus final</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>Class modifiers for API maintainers</h1></div><div id="site-toc--inline" class="site-toc"><header class="site-toc__title">Contents</header><ul class="section-nav"><li class="toc-entry"><a href="#the-mixin-modifier-on-classes">The mixin modifier on classes</a><ul><li class="toc-entry"><a href="#migrating-classes-as-mixins">Migrating classes as mixins</a></li></ul></li><li class="toc-entry"><a href="#other-opt-in-modifiers">Other opt-in modifiers</a></li><li class="toc-entry"><a href="#the-interface-modifier">The interface modifier</a></li><li class="toc-entry"><a href="#the-base-modifier">The base modifier</a><ul><li class="toc-entry"><a href="#base-transitivity">Base transitivity</a></li></ul></li><li class="toc-entry"><a href="#the-final-modifier">The final modifier</a></li><li class="toc-entry"><a href="#the-sealed-modifier">The sealed modifier</a><ul><li class="toc-entry"><a href="#sealed-versus-final">sealed versus final</a></li></ul></li><li class="toc-entry"><a href="#summary">Summary</a></li></ul></div><p>Dart 3.0 adds a few <a href="/language/class-modifiers">new modifiers</a> that you can place on class and <a href="/language/mixins">mixin declarations</a>. If you are the author of a library package, these modifiers give you more control over what users are allowed to do with the types that your package exports. This can make it easier to evolve your package, and easier to know if a change to your code may break users.</p><p>Dart 3.0 also includes a <a href="/resources/dart-3-migration#mixin">breaking change</a> around using classes as mixins. This change might not break <em>your</em> class, but it could break <em>users</em> of your class.</p><p>This guide walks you through these changes so you know how to use the new modifiers, and how they affect users of your libraries.</p><div class="header-wrapper"><h2 id="the-mixin-modifier-on-classes">The <code>mixin</code> modifier on classes</h2><a class="heading-link" href="#the-mixin-modifier-on-classes" aria-label="Link to 'The mixin modifier on classes' section">#</a></div><p>The most important modifier to be aware of is <code>mixin</code>. Language versions prior to Dart 3.0 allow any class to be used as a mixin in another class's <code>with</code> clause, <em>UNLESS</em> the class:</p><ul><li>Declares any non-factory constructors.</li><li>Extends any class other than <code>Object</code>.</li></ul><p>This makes it easy to accidentally break someone else's code, by adding a constructor or <code>extends</code> clause to a class without realizing that others are using it in a <code>with</code> clause.</p><p>Dart 3.0 no longer allows classes to be used as mixins by default. Instead, you must explicitly opt-in to that behavior by declaring a <code>mixin class</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:#D43324">mixin</span><span style="color:#D43324"> class</span><span style="color:#0468D7"> Both</span><span style="color:#222222"> {}</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> UseAsMixin</span><span style="color:#D43324"> with</span><span style="color:#0468D7"> Both</span><span style="color:#222222"> {}</span></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> UseAsSuperclass</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> Both</span><span style="color:#222222"> {}</span></span></code></pre></div></div><p>If you update your package to Dart 3.0 and don't change any of your code, you may not see any errors. But you may inadvertently break users of your package if they were using your classes as mixins.</p><div class="header-wrapper"><h3 id="migrating-classes-as-mixins">Migrating classes as mixins</h3><a class="heading-link" href="#migrating-classes-as-mixins" aria-label="Link to 'Migrating classes as mixins' section">#</a></div><p>If the class has a non-factory constructor, an <code>extends</code> clause, or a <code>with</code> clause, then it already can't be used as a mixin. Behavior won't change with Dart 3.0; there's nothing to worry about and nothing you need to do.</p><p>In practice, this describes about 90% of existing classes. For the remaining classes that can be used as mixins, you have to decide what you want to support.</p><p>Here are a few questions to help decide. The first is pragmatic:</p><ul><li><strong>Do you want to risk breaking any users?</strong> If the answer is a hard "no", then place <code>mixin</code> before any and all classes that <a href="#the-mixin-modifier-on-classes">could be used as a mixin</a>. This exactly preserves the existing behavior of your API.</li></ul><p>On the other hand, if you want to take this opportunity to rethink the affordances your API offers, then you may want to <em>not</em> turn it into a <code>mixin class</code>. Consider these two design questions:</p><ul><li><p><strong>Do you want users to be able to construct instances of it directly?</strong> In other words, is the class deliberately not abstract?</p></li><li><p><strong>Do you <em>want</em> people to be able to use the declaration as a mixin?</strong> In other words, do you want them to be able to use it in <code>with</code> clauses?</p></li></ul><p>If the answer to both is "yes", then make it a mixin class. If the answer to the second is "no", then just leave it as a class. If the answer to the first is "no" and the second is "yes", then change it from a class to a mixin declaration.</p><p>The last two options, leaving it a class or turning it into a pure mixin, are breaking API changes. You'll want to bump the major version of your package if you do this.</p><div class="header-wrapper"><h2 id="other-opt-in-modifiers">Other opt-in modifiers</h2><a class="heading-link" href="#other-opt-in-modifiers" aria-label="Link to 'Other opt-in modifiers' section">#</a></div><p>Handling classes as mixins is the only critical change in Dart 3.0 that affects the API of your package. Once you've gotten this far, you can stop if you don't want to make other changes to what your package allows users to do.</p><p>Note that if you do continue and use any of the modifiers described below, it is potentially a breaking change to your package's API which necessitates a major version increment.</p><div class="header-wrapper"><h2 id="the-interface-modifier">The <code>interface</code> modifier</h2><a class="heading-link" href="#the-interface-modifier" aria-label="Link to 'The interface modifier' section">#</a></div><p>Dart doesn't have a separate syntax for declaring pure interfaces. Instead, you declare an abstract class that happens to contain only abstract methods. When a user sees that class in your package's API, they may not know if it contains code they can reuse by extending the class, or whether it is instead meant to be used as an interface.</p><p>You can clarify that by putting the <a href="/language/class-modifiers#interface"><code>interface</code></a> modifier on the class. That allows the class to be used in an <code>implements</code> clause, but prevents it from being used in <code>extends</code>.</p><p>Even when the class <em>does</em> have non-abstract methods, you may want to prevent users from extending it. Inheritance is one of the most powerful kinds of coupling in software, because it enables code reuse. But that coupling is also <a href="https://en.wikipedia.org/wiki/Fragile_base_class">dangerous and fragile</a>. When inheritance crosses package boundaries, it can be hard to evolve the superclass without breaking subclasses.</p><p>Marking the class <code>interface</code> lets users construct it (unless it's <a href="/language/class-modifiers#abstract-interface">also marked <code>abstract</code></a>) and implement the class's interface, but prevents them from reusing any of its code.</p><p>When a class is marked <code>interface</code>, the restriction can be ignored within the library where the class is declared. Inside the library, you're free to extend it since it's all your code and presumably you know what you're doing. The restriction applies to other packages, and even other libraries within your own package.</p><div class="header-wrapper"><h2 id="the-base-modifier">The <code>base</code> modifier</h2><a class="heading-link" href="#the-base-modifier" aria-label="Link to 'The base modifier' section">#</a></div><p>The <a href="/language/class-modifiers#base"><code>base</code></a> modifier is somewhat the opposite of <code>interface</code>. It allows you to use the class in an <code>extends</code> clause, or use a mixin or mixin class in a <code>with</code> clause. But, it disallows code outside of the class's library from using the class or mixin in an <code>implements</code> clause.</p><p>This ensures that every object that is an instance of your class or mixin's interface inherits your actual implementation. In particular, this means that every instance will include all of the private members your class or mixin declares. This can help prevent runtime errors that might otherwise occur.</p><p>Consider this library:</p><div class="code-block-wrapper language-dart"><div class="code-block-header">a.dart</div><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> A</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> _privateMethod</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">'I inherited from A'</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> callPrivateMethod</span><span style="color:#222222">(</span><span style="color:#0468D7">A</span><span style="color:#222222"> a) {</span></span> <span class="line"><span style="color:#222222"> a.</span><span style="color:#6200EE">_privateMethod</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>This code seems fine on its own, but there's nothing preventing a user from creating another library like this:</p><div class="code-block-wrapper language-dart"><div class="code-block-header">b.dart</div><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">import</span><span style="color:#11796D"> 'a.dart'</span><span style="color:#222222">;</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> B</span><span style="color:#D43324"> implements</span><span style="color:#0468D7"> A</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#6E6E70"> // No implementation of _privateMethod()!</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#6200EE">main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#6200EE"> callPrivateMethod</span><span style="color:#222222">(</span><span style="color:#0468D7">B</span><span style="color:#222222">()); </span><span style="color:#6E6E70">// Runtime exception!</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Adding the <code>base</code> modifier to the class can help prevent these runtime errors. As with <code>interface</code>, you can ignore this restriction in the same library where the <code>base</code> class or mixin is declared. Then subclasses in the same library will be reminded to implement the private methods. But note that the next section <em>does</em> apply:</p><div class="header-wrapper"><h3 id="base-transitivity">Base transitivity</h3><a class="heading-link" href="#base-transitivity" aria-label="Link to 'Base transitivity' section">#</a></div><p>The goal of marking a class <code>base</code> is to ensure that every instance of that type concretely inherits from it. To maintain this, the base restriction is "contagious". Every subtype of a type marked <code>base</code> -- <em>direct or indirect</em> -- must also prevent being implemented. That means it must be marked <code>base</code> (or <code>final</code> or <code>sealed</code>, which we'll get to next).</p><p>Applying <code>base</code> to a type requires some care, then. It affects not just what users can do with your class or mixin, but also the affordances <em>their</em> subclasses can offer. Once you've put <code>base</code> on a type, the whole hierarchy under it is prohibited from being implemented.</p><p>That sounds intense, but it's how most other programming languages have always worked. Most don't have implicit interfaces at all, so when you declare a class in Java, C#, or other languages, you effectively have the same constraint.</p><div class="header-wrapper"><h2 id="the-final-modifier">The <code>final</code> modifier</h2><a class="heading-link" href="#the-final-modifier" aria-label="Link to 'The final modifier' section">#</a></div><p>If you want all of the restrictions of both <code>interface</code> and <code>base</code>, you can mark a class or mixin class <a href="/language/class-modifiers#final"><code>final</code></a>. This prevents anyone outside of your library from creating any kind of subtype of it: no using it in <code>implements</code>, <code>extends</code>, <code>with</code>, or <code>on</code> clauses.</p><p>This is the most restrictive for users of the class. All they can do is construct it (unless it's marked <code>abstract</code>). In return, you have the fewest restrictions as the class maintainer. You can add new methods, turn constructors into factory constructors, etc. without worrying about breaking any downstream users.</p><p><a id="the-sealed-modifer"></a></p><div class="header-wrapper"><h2 id="the-sealed-modifier">The <code>sealed</code> modifier</h2><a class="heading-link" href="#the-sealed-modifier" aria-label="Link to 'The sealed modifier' section">#</a></div><p>The last modifier, <a href="/language/class-modifiers#sealed"><code>sealed</code></a>, is special. It exists primarily to enable <a href="/language/branches#exhaustiveness-checking">exhaustiveness checking</a> in pattern matching. If a switch has cases for every direct subtype of a type marked <code>sealed</code>, then the compiler knows the switch is exhaustive.</p> <?code-excerpt "language/lib/class_modifiers/sealed_exhaustiveness.dart"?> <div class="code-block-wrapper language-dart"><div class="code-block-header">amigos.dart</div><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">sealed</span><span style="color:#D43324"> class</span><span style="color:#0468D7"> Amigo</span><span style="color:#222222"> {}</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Lucky</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> Amigo</span><span style="color:#222222"> {}</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Dusty</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> Amigo</span><span style="color:#222222"> {}</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Ned</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> Amigo</span><span style="color:#222222"> {}</span></span> <span class="line"></span> <span class="line"><span style="color:#0468D7">String</span><span style="color:#6200EE"> lastName</span><span style="color:#222222">(</span><span style="color:#0468D7">Amigo</span><span style="color:#222222"> amigo) => </span><span style="color:#D43324">switch</span><span style="color:#222222"> (amigo) {</span></span> <span class="line"><span style="color:#0468D7"> Lucky</span><span style="color:#222222"> _ => </span><span style="color:#11796D">'Day'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#0468D7"> Dusty</span><span style="color:#222222"> _ => </span><span style="color:#11796D">'Bottoms'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#0468D7"> Ned</span><span style="color:#222222"> _ => </span><span style="color:#11796D">'Nederlander'</span><span style="color:#222222">,</span></span> <span class="line"><span style="color:#222222">};</span></span></code></pre></div></div><p>This switch has a case for each of the subtypes of <code>Amigo</code>. The compiler knows that every instance of <code>Amigo</code> must be an instance of one of those subtypes, so it knows the switch is safely exhaustive and doesn't require any final default case.</p><p>For this to be sound, the compiler enforces two restrictions:</p><ol><li><p>The sealed class can't itself be directly constructible. Otherwise, you could have an instance of <code>Amigo</code> that isn't an instance of <em>any</em> of the subtypes. So every <code>sealed</code> class is implicitly <code>abstract</code> too.</p></li><li><p>Every direct subtype of the sealed type must be in the same library where the sealed type is declared. This way, the compiler can find them all. It knows that there aren't other hidden subtypes floating around that would not match any of the cases.</p></li></ol><p>The second restriction is similar to <code>final</code>. Like <code>final</code>, it means that a class marked <code>sealed</code> can't be directly extended, implemented, or mixed in outside of the library where it's declared. But, unlike <code>base</code> and <code>final</code>, there is no <em>transitive</em> restriction:</p><div class="code-block-wrapper language-dart"><div class="code-block-header">amigo.dart</div><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">sealed</span><span style="color:#D43324"> class</span><span style="color:#0468D7"> Amigo</span><span style="color:#222222"> {}</span></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Lucky</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> Amigo</span><span style="color:#222222"> {}</span></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Dusty</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> Amigo</span><span style="color:#222222"> {}</span></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Ned</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> Amigo</span><span style="color:#222222"> {}</span></span></code></pre></div></div><div class="code-block-wrapper language-dart"><div class="code-block-header">other.dart</div><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#6E6E70">// This is an error:</span></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Bad</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> Amigo</span><span style="color:#222222"> {}</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">// But these are both fine:</span></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> OtherLucky</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> Lucky</span><span style="color:#222222"> {}</span></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> OtherDusty</span><span style="color:#D43324"> implements</span><span style="color:#0468D7"> Dusty</span><span style="color:#222222"> {}</span></span></code></pre></div></div><p>Of course, if you <em>want</em> the subtypes of your sealed type to be restricted as well, you can get that by marking them using <code>interface</code>, <code>base</code>, <code>final</code>, or <code>sealed</code>.</p><div class="header-wrapper"><h3 id="sealed-versus-final"><code>sealed</code> versus <code>final</code></h3><a class="heading-link" href="#sealed-versus-final" aria-label="Link to 'sealed versus final' section">#</a></div><p>If you have a class that you don't want users to be able to directly subtype, when should you use <code>sealed</code> versus <code>final</code>? A couple of simple rules:</p><ul><li><p>If you want users to be able to directly construct instances of the class, then it <em>can't</em> use <code>sealed</code> since sealed types are implicitly abstract.</p></li><li><p>If the class has no subtypes in your library, then there's no point in using <code>sealed</code> since you get no exhaustiveness checking benefits.</p></li></ul><p>Otherwise, if the class does have some subtypes that you define, then <code>sealed</code> is likely what you want. If users see that the class has a few subtypes, it's handy to be able to handle each of them separately as switch cases and have the compiler know that the entire type is covered.</p><p>Using <code>sealed</code> does mean that if you later add another subtype to the library, it's a breaking API change. When a new subtype appears, all of those existing switches become non-exhaustive since they don't handle the new type. It's exactly like adding a new value to an enum.</p><p>Those non-exhaustive switch compile errors are <em>useful</em> to users because they draw the user's attention to places in their code where they'll need to handle the new type.</p><p>But it does mean that whenever you add a new subtype, it's a breaking change. If you want the freedom to add new subtypes in a non-breaking way, then it's better to mark the supertype using <code>final</code> instead of <code>sealed</code>. That means that when a user switches on a value of that supertype, even if they have cases for all of the subtypes, the compiler will force them to add another default case. That default case will then be what is executed if you add more subtypes later.</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>As an API designer, these new modifiers give you control over how users work with your code, and conversely how you are able to evolve your code without breaking theirs.</p><p>But these options carry complexity with them: you now have more choices to make as an API designer. Also, since these features are new, we still don't know what the best practices will be. Every language's ecosystem is different and has different needs.</p><p>Fortunately, you don't need to figure it out all at once. We chose the defaults deliberately so that even if you do nothing, your classes mostly have the same affordances they had before 3.0. If you just want to keep your API the way it was, put <code>mixin</code> on the classes that already supported that, and you're done.</p><p>Over time, as you get a sense of where you want finer control, you can consider applying some of the other modifiers:</p><ul><li><p>Use <code>interface</code> to prevent users from reusing your class's code while allowing them to re-implement its interface.</p></li><li><p>Use <code>base</code> to require users to reuse your class's code and ensure every instance of your class's type is an instance of that actual class or a subclass.</p></li><li><p>Use <code>final</code> to completely prevent a class from being extended.</p></li><li><p>Use <code>sealed</code> to opt in to exhaustiveness checking on a family of subtypes.</p></li></ul><p>When you do, increment the major version when publishing your package, since these modifiers all imply restrictions that are breaking changes.</p><nav id="prev-next"><ul><li class="previous"><a href="/language/class-modifiers">⟨ Class modifiers</a></li><li class="next"><a href="/language/modifier-reference">Class modifiers reference ⟩</a></li></ul></nav><p id="page-github-links"><span>Unless stated otherwise, the documentation on this site reflects Dart 3.7.2. Page last updated on 2025-02-12.</span> <a href="https://github.com/dart-lang/site-www/tree/main/src/content/language/class-modifiers-for-apis.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/language/class-modifiers-for-apis/&page-source=https://github.com/dart-lang/site-www/tree/main/src/content/language/class-modifiers-for-apis.md" title="Report an issue with this page" target="_blank" rel="noopener">report an issue</a>.</p></div></article></main></div><footer id="page-footer"><div class="footer-section footer-main"><a href="/" class="brand" title="Dart"><img src="/assets/img/logo/logo-white-text.svg" alt="Dart" width="164"></a><div class="footer-social-links"><a href="https://medium.com/dartlang" target="_blank" rel="noopener" title="Dart's Medium publication"><svg><use href="/assets/img/social/medium.svg#medium"></use></svg> </a><a href="https://github.com/dart-lang" target="_blank" rel="noopener" title="Dart's GitHub organization"><svg><use href="/assets/img/social/github.svg#github"></use></svg> </a><a href="https://bsky.app/profile/dart.dev" target="_blank" rel="noopener" title="Dart's Bluesky profile"><svg><use href="/assets/img/social/bluesky.svg#bluesky"></use></svg> </a><a href="https://twitter.com/dart_lang" target="_blank" rel="noopener" title="Dart's X (Twitter) profile"><svg><use href="/assets/img/social/x.svg#x"></use></svg></a></div></div><div class="footer-section footer-tray"><div class="footer-licenses">Except as otherwise noted, this site is licensed under a <a href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>, and code samples are licensed under the <a href="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</a>.</div><div class="footer-utility-links"><ul><li><a href="/terms" title="Terms of use">Terms</a></li><li><a href="https://policies.google.com/privacy" target="_blank" rel="noopener" title="Privacy policy">Privacy</a></li><li><a href="/security" title="Security philosophy and practices">Security</a></li></ul></div></div></footer></div></body></html>