Dart / Flutter Coding Standards¶
Revision 1.0 โ July 2026
This is a delta document against the C++ Coding Standards. Everything not restated here applies unchanged: general principles (ยง1.1), comment discipline (ยง2), error handling philosophy (ยง7), and tooling expectations (ยง12). Where Dart idiom conflicts with the C++ rule, this document wins for Dart code.
The primary reference is the official Dart style guide โ Effective Dart is the baseline; this document only records where the workspace deviates from it.
1. Scope¶
Applies to all Dart code in the workspace: Flutter apps (GeniusWallet,
genius-tube UI), reusable packages under GeniusWallet/packages/, and
generated-code templates that emit Dart.
Rules keep the same classifications as the C++ standard: Required / Recommended.
2. Deltas from the C++ Standard¶
2.1 Bracing โ Allman does NOT apply¶
Required: Dart uses K&R / same-line braces (the dartfmt default), not Allman. This is the single biggest visual delta from the C++ standard.
// Dart โ correct
if (isReady) {
play();
} else {
buffer();
}
// NOT the C++ Allman style:
// if (isReady)
// {
// play();
// }
Required: Never hand-format around dartfmt. Run dart format (or have the
IDE apply it) before commit. If dartfmt's output looks wrong, the code is too
clever โ simplify the code, not the formatter's output.
2.2 Naming¶
Dart has its own naming conventions; follow them rather than the C++ table:
| Construct | Style | Example | Classification |
|---|---|---|---|
| Types (classes, enums, typedefs, mixins, extensions) | PascalCase | PlaybackLease |
Required |
| Functions, methods, variables, parameters | camelCase | resolveEntitlement() |
Required |
| Members (fields) | camelCase, no prefix | nodeId |
Required |
| Private members | leading _ |
_contentKey |
Required |
Constants (const/static const) |
camelCase | defaultEpochLength |
Required |
| Files and directories | snake_case | playback_lease.dart |
Required |
| Packages | snake_case | genius_api |
Required |
Deltas to note explicitly:
- No
m_prefix. Dart marks privacy with leading_, not scope with a prefix. A private field is_nodeId; a public one isnodeId. - No
kprefix on constants. Dart style is plain camelCase (defaultEpochLength, notkDefaultEpochLength). - Functions are camelCase, where the C++ standard uses PascalCase.
- Files are snake_case, matching the C++ standard's file rule.
2.3 Types and null safety¶
Required: Sound null safety everywhere. No // @dart=2.x opt-outs, no
late without an initializer in the constructor path, no ! unless the
alternative is measurably worse. Prefer making the type honest (nullable or
not) over asserting at use sites.
Required: Prefer final fields and const constructors where the object
is immutable โ view models and event/command structs crossing the FFI boundary
should be immutable value types.
Recommended: Use Dart 3 records and sealed classes for the typed
command/event envelopes that mirror the C++ core's FFI structs. Sealed classes
give exhaustive switch checking for free.
2.4 Error handling¶
Mirrors C++ ยง7 with Dart mechanics:
Required: Errors that cross the FFI boundary arrive as values (the
GeniusTubeError-style struct via ffigen), not exceptions. Convert them to
typed Dart results or throw typed exceptions at the repository/facade
layer โ widgets should never see raw FFI error structs.
Required: Exceptions thrown in Dart use typed exception classes
(class EntitlementException implements Exception), never bare strings or
generic Exception() instances.
Recommended: Retryability comes from the core's error-code functions via FFI. Do not hand-maintain a Dart copy of the error taxonomy โ the C++ core is the single source of truth.
2.5 Comments¶
Same as C++ ยง2 with Dart syntax, using Doxygen-style comments rather than
dartdoc. Our documentation pipeline (gendoc-template) is Doxygen-based; the
/// dartdoc convention is not consumed by our tooling, so we standardize on
Doxygen format for all workspace languages including Dart.
Required: Every file has a top-of-file Doxygen comment. Public APIs have
Doxygen /** ... */ block comments in the declaring file.
/**
* @file playback_lease.dart
* @brief Playback-lease resolution against the on-chain entitlement registry.
*/
/**
* @brief Resolves the current holder's entitlement for [assetId] against the
* chain, returning a lease ready for playback.
* @param assetId The asset whose entitlement is being resolved.
* @return A [Future] completing with the resolved [PlaybackLease].
* @throws [EntitlementException] when ownership cannot be proven.
*/
Future<PlaybackLease> resolveEntitlement(String assetId) { ... }
Recommended: Inline comments use //, same as C++.
2.6 Flutter-specific rules¶
Required: Widgets contain no protocol, ledger, DRM, or CRDT logic. A widget reads a view model, renders it, and dispatches a typed command. All state transitions happen in the C++ core and arrive as typed events.
Required: State management is provider with immutable view models.
Avoid adding heavier frameworks (bloc, riverpod, getx) โ one pattern
workspace-wide.
Recommended: Keep widgets small; extract a new widget before a build method exceeds a screen of code, same spirit as the C++ function-size rule.
Recommended: const constructors on widgets wherever possible โ it is
the cheapest Flutter performance win and costs nothing.
3. Generated Dart¶
FFI bindings and schema-driven Dart are generated (ffigen / Jinja2) and are never committed. Do not hand-edit generated files โ change the template or the config and regenerate. Generated files carry the source-schema and generator-version header, same as generated C++.
4. Tooling¶
| Tool | Purpose |
|---|---|
dart format |
Formatting โ run before commit, no config debates |
dart analyze (analysis_options.yaml with package:flutter_lints) |
Static analysis โ Required-clean |
flutter test |
Unit/widget tests |
| ffigen | FFI binding regeneration (driven by CMake stamp targets) |
analysis_options.yaml lives at the package root and includes
package:flutter_lints/flutter.yaml. Deviations from a lint require a
// ignore: <lint> comment with a reason on the same line โ same discipline
as the C++ standard's clang-tidy suppression rule.
5. References¶
- Effective Dart โ the baseline this document deltas from
- C++ Coding Standards โ parent document
GeniusWallet/packages/genius_api/โ reference package structure and ffigen consumption pattern