From fa3a5cdc94e36cadfd08c8725bc3c587761d34b9 Mon Sep 17 00:00:00 2001 From: Dmytro Turskyi Date: Sun, 7 Jan 2024 12:04:09 -0500 Subject: [PATCH 1/3] =?UTF-8?q?Reorder=20constructors=20in=20=E2=80=98Effe?= =?UTF-8?q?ctive=20Dart:=20Usage=E2=80=99=20examples?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In this commit, I have reordered the constructors in all examples on the ‘Effective Dart: Usage’ page to align with the Dart and Flutter style guides. Specifically, I followed the guidelines from ‘sort_constructors_first’ (https://dart.dev/tools/linter-rules/sort_constructors_first), ‘sort_unnamed_constructors_first’ (https://dart.dev/tools/linter-rules/sort_unnamed_constructors_first), ‘Constructors come first in a class’ (https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#constructors-come-first-in-a-class) and `Order other class members in a way that makes sense` (https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#order-other-class-members-in-a-way-that-makes-sense). By placing constructors before other class members, these examples now adhere to the recommended style and provide clearer, more consistent code for Dart and Flutter developers. --- src/effective-dart/usage.md | 68 ++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/src/effective-dart/usage.md b/src/effective-dart/usage.md index 91e810b7a4..7faff0c734 100644 --- a/src/effective-dart/usage.md +++ b/src/effective-dart/usage.md @@ -366,10 +366,10 @@ so you can safely treat it as non-nullable. ```dart class UploadException { - final Response? response; - UploadException([this.response]); + final Response? response; + @override String toString() { final response = this.response; @@ -390,10 +390,10 @@ time you need to treat the value as non-null: ```dart class UploadException { - final Response? response; - UploadException([this.response]); + final Response? response; + @override String toString() { if (response != null) { @@ -979,14 +979,14 @@ constructor and then stores them: ```dart class Circle { - double radius; - double area; - double circumference; - Circle(double radius) : radius = radius, area = pi * radius * radius, circumference = pi * 2.0 * radius; + + double radius; + double area; + double circumference; } ``` @@ -1007,6 +1007,10 @@ To correctly handle cache invalidation, we would need to do this: ```dart class Circle { + Circle(this._radius) { + _recalculate(); + } + double _radius; double get radius => _radius; set radius(double value) { @@ -1020,10 +1024,6 @@ class Circle { double _circumference = 0.0; double get circumference => _circumference; - Circle(this._radius) { - _recalculate(); - } - void _recalculate() { _area = pi * _radius * _radius; _circumference = pi * 2.0 * _radius; @@ -1038,10 +1038,10 @@ first implementation should be: ```dart class Circle { - double radius; - Circle(this.radius); + double radius; + double get area => pi * radius * radius; double get circumference => pi * 2.0 * radius; } @@ -1228,14 +1228,14 @@ The other time to use `this.` is when redirecting to a named constructor: ```dart class ShadeOfGray { - final int brightness; - ShadeOfGray(int val) : brightness = val; ShadeOfGray.black() : this(0); // This won't parse or compile! // ShadeOfGray.alsoBlack() : black(); + + final int brightness; } ``` @@ -1243,14 +1243,14 @@ class ShadeOfGray { ```dart class ShadeOfGray { - final int brightness; - ShadeOfGray(int val) : brightness = val; ShadeOfGray.black() : this(0); // But now it will! ShadeOfGray.alsoBlack() : this.black(); + + final int brightness; } ``` @@ -1261,11 +1261,11 @@ lists: ```dart class Box extends BaseBox { - Object? value; - Box(Object? value) : value = value, super(value); + + Object? value; } ``` @@ -1283,13 +1283,13 @@ the class has multiple constructors. ```dart class ProfileMark { - final String name; - final DateTime start; - ProfileMark(this.name) : start = DateTime.now(); ProfileMark.unnamed() : name = '', start = DateTime.now(); + + final String name; + final DateTime start; } ``` @@ -1297,11 +1297,11 @@ class ProfileMark { ```dart class ProfileMark { - final String name; - final DateTime start = DateTime.now(); - ProfileMark(this.name); ProfileMark.unnamed() : name = ''; + + final String name; + final DateTime start = DateTime.now(); } ``` @@ -1327,10 +1327,11 @@ Many fields are initialized directly from a constructor parameter, like: ```dart class Point { - double x, y; Point(double x, double y) : x = x, y = y; + + double x, y; } ``` @@ -1340,8 +1341,9 @@ We've got to type `x` _four_ times here to define a field. We can do better: ```dart class Point { - double x, y; Point(this.x, this.y); + + double x, y; } ``` @@ -1367,10 +1369,11 @@ initialize the field in the constructor initializer list: ```dart class Point { - double x, y; Point.polar(double theta, double radius) : x = cos(theta) * radius, y = sin(theta) * radius; + + double x, y; } ``` @@ -1378,11 +1381,12 @@ class Point { ```dart class Point { - late double x, y; Point.polar(double theta, double radius) { x = cos(theta) * radius; y = sin(theta) * radius; } + + late double x, y; } ``` @@ -1404,8 +1408,8 @@ semicolon. (In fact, it's required for const constructors.) ```dart class Point { - double x, y; Point(this.x, this.y); + double x, y; } ``` @@ -1413,8 +1417,8 @@ class Point { ```dart class Point { - double x, y; Point(this.x, this.y) {} + double x, y; } ``` From f66933f516fc0207d972e8d5f791290ec101fd8f Mon Sep 17 00:00:00 2001 From: Dmytro Turskyi Date: Sun, 7 Jan 2024 17:51:01 -0500 Subject: [PATCH 2/3] =?UTF-8?q?Refactor=20placement=20of=20field=20declara?= =?UTF-8?q?tions,=20following=20the=20guidelines=20from=20=E2=80=98sort=5F?= =?UTF-8?q?constructors=5Ffirst=E2=80=99=20(https://dart.dev/tools/linter-?= =?UTF-8?q?rules/sort=5Fconstructors=5Ffirst),=20=E2=80=98sort=5Funnamed?= =?UTF-8?q?=5Fconstructors=5Ffirst=E2=80=99=20(https://dart.dev/tools/lint?= =?UTF-8?q?er-rules/sort=5Funnamed=5Fconstructors=5Ffirst),=20=E2=80=98Con?= =?UTF-8?q?structors=20come=20first=20in=20a=20class=E2=80=99=20(https://g?= =?UTF-8?q?ithub.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#con?= =?UTF-8?q?structors-come-first-in-a-class)=20and=20Order=20other=20class?= =?UTF-8?q?=20members=20in=20a=20way=20that=20makes=20sense=20(https://git?= =?UTF-8?q?hub.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#order?= =?UTF-8?q?-other-class-members-in-a-way-that-makes-sense).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reorganized field declarations to improve readability and adhere to Dart language conventions. This change enhances the consistency across examples for both 'good' and 'bad' usage cases, clarifying the correct use of field initialization. No functional changes; this refactoring solely aims at improving the codebase maintainability and educative quality. Signed-off-by: Dmytro Turskyi --- .../misc/lib/effective_dart/usage_bad.dart | 36 ++++++++++--------- .../misc/lib/effective_dart/usage_good.dart | 30 ++++++++-------- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/examples/misc/lib/effective_dart/usage_bad.dart b/examples/misc/lib/effective_dart/usage_bad.dart index 338741eead..eef175ce9e 100644 --- a/examples/misc/lib/effective_dart/usage_bad.dart +++ b/examples/misc/lib/effective_dart/usage_bad.dart @@ -272,14 +272,14 @@ void miscDeclAnalyzedButNotTested() { // #docregion this-dot-constructor class ShadeOfGray { - final int brightness; - ShadeOfGray(int val) : brightness = val; ShadeOfGray.black() : this(0); // This won't parse or compile! // ShadeOfGray.alsoBlack() : black(); + + final int brightness; } // #enddocregion this-dot-constructor @@ -330,10 +330,10 @@ Item? bestDeal(List cart) { // #docregion shadow-nullable-field class UploadException { - final Response? response; - UploadException([this.response]); + final Response? response; + @override String toString() { if (response != null) { @@ -350,14 +350,14 @@ class UploadException { // #docregion calc-vs-store1 class Circle1 { - double radius; - double area; - double circumference; - Circle1(double radius) : radius = radius, area = pi * radius * radius, circumference = pi * 2.0 * radius; + + double radius; + double area; + double circumference; } // #enddocregion calc-vs-store1 @@ -365,6 +365,10 @@ class Circle1 { // #docregion calc-vs-store2 class Circle2 { + Circle2(this._radius) { + _recalculate(); + } + double _radius; double get radius => _radius; set radius(double value) { @@ -378,10 +382,6 @@ class Circle2 { double _circumference = 0.0; double get circumference => _circumference; - Circle2(this._radius) { - _recalculate(); - } - void _recalculate() { _area = pi * _radius * _radius; _circumference = pi * 2.0 * _radius; @@ -430,13 +430,13 @@ class Box2 { // #docregion field-init-at-decl class ProfileMark { - final String name; - final DateTime start; - ProfileMark(this.name) : start = DateTime.now(); ProfileMark.unnamed() : name = '', start = DateTime.now(); + + final String name; + final DateTime start; } // #enddocregion field-init-at-decl @@ -444,10 +444,11 @@ class ProfileMark { // #docregion field-init-as-param class Point0 { - double x, y; Point0(double x, double y) : x = x, y = y; + + double x, y; } // #enddocregion field-init-as-param @@ -455,11 +456,12 @@ class Point0 { // #docregion late-init-list class Point1 { - late double x, y; Point1.polar(double theta, double radius) { x = cos(theta) * radius; y = sin(theta) * radius; } + + late double x, y; } // #enddocregion late-init-list diff --git a/examples/misc/lib/effective_dart/usage_good.dart b/examples/misc/lib/effective_dart/usage_good.dart index f8456f13bf..e51add5042 100644 --- a/examples/misc/lib/effective_dart/usage_good.dart +++ b/examples/misc/lib/effective_dart/usage_good.dart @@ -359,10 +359,10 @@ class Response { // #docregion shadow-nullable-field class UploadException { - final Response? response; - UploadException([this.response]); + final Response? response; + @override String toString() { final response = this.response; @@ -380,10 +380,10 @@ class UploadException { // #docregion calc-vs-store class Circle { - double radius; - Circle(this.radius); + double radius; + double get area => pi * radius * radius; double get circumference => pi * 2.0 * radius; } @@ -466,14 +466,14 @@ class Box2 { // #docregion this-dot-constructor class ShadeOfGray { - final int brightness; - ShadeOfGray(int val) : brightness = val; ShadeOfGray.black() : this(0); // But now it will! ShadeOfGray.alsoBlack() : this.black(); + + final int brightness; } // #enddocregion this-dot-constructor @@ -485,11 +485,11 @@ class BaseBox { // #docregion param-dont-shadow-field-ctr-init class Box3 extends BaseBox { - Object? value; - Box3(Object? value) : value = value, super(value); + + Object? value; } // #enddocregion param-dont-shadow-field-ctr-init @@ -499,11 +499,11 @@ class Document {} // #docregion field-init-at-decl class ProfileMark { - final String name; - final DateTime start = DateTime.now(); - ProfileMark(this.name); ProfileMark.unnamed() : name = ''; + + final String name; + final DateTime start = DateTime.now(); } // #enddocregion field-init-at-decl @@ -511,8 +511,9 @@ class ProfileMark { // #docregion field-init-as-param class Point0 { - double x, y; Point0(this.x, this.y); + + double x, y; } // #enddocregion field-init-as-param @@ -520,10 +521,11 @@ class Point0 { // #docregion late-init-list class Point1 { - double x, y; Point1.polar(double theta, double radius) : x = cos(theta) * radius, y = sin(theta) * radius; + + double x, y; } // #enddocregion late-init-list @@ -531,8 +533,8 @@ class Point1 { // #docregion semicolon-for-empty-body class Point2 { - double x, y; Point2(this.x, this.y); + double x, y; } // #enddocregion semicolon-for-empty-body From 60253fc712cdfeea4e7e8e8a28a70a09caab7aef Mon Sep 17 00:00:00 2001 From: Dmytro Turskyi Date: Sun, 7 Jan 2024 18:36:00 -0500 Subject: [PATCH 3/3] Refactor class fields for consistency. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adopted best practices for consistent placement of constructors, following the guidelines from ‘sort_constructors_first’ (https://dart.dev/tools/linter-rules/sort_constructors_first), ‘sort_unnamed_constructors_first’ (https://dart.dev/tools/linter-rules/sort_unnamed_constructors_first), ‘Constructors come first in a class’ (https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#constructors-come-first-in-a-class) and Order other class members in a way that makes sense (https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#order-other-class-members-in-a-way-that-makes-sense). No functional impact, purely organizational changes to enhance clarity. Signed-off-by: Dmytro Turskyi --- .../lib/language_tour/classes/employee.dart | 4 +- .../classes/immutable_point.dart | 4 +- .../lib/language_tour/classes/logger.dart | 14 ++--- .../misc/lib/language_tour/classes/point.dart | 6 +- .../lib/language_tour/classes/point_alt.dart | 6 +- .../classes/point_redirecting.dart | 4 +- .../classes/point_with_distance_field.dart | 8 +-- .../classes/super_initializer_parameters.dart | 27 +++++---- src/language/constructors.md | 60 +++++++++---------- 9 files changed, 69 insertions(+), 64 deletions(-) diff --git a/examples/misc/lib/language_tour/classes/employee.dart b/examples/misc/lib/language_tour/classes/employee.dart index 1356715624..92e67a5e11 100644 --- a/examples/misc/lib/language_tour/classes/employee.dart +++ b/examples/misc/lib/language_tour/classes/employee.dart @@ -4,11 +4,11 @@ Map fetchDefaultData() => {}; // stub // #docregion super class Person { - String? firstName; - Person.fromJson(Map data) { print('in Person'); } + + String? firstName; } // #docregion method-then-constructor diff --git a/examples/misc/lib/language_tour/classes/immutable_point.dart b/examples/misc/lib/language_tour/classes/immutable_point.dart index 813c608611..0d27d293c7 100644 --- a/examples/misc/lib/language_tour/classes/immutable_point.dart +++ b/examples/misc/lib/language_tour/classes/immutable_point.dart @@ -1,7 +1,7 @@ class ImmutablePoint { + const ImmutablePoint(this.x, this.y); + static const ImmutablePoint origin = ImmutablePoint(0, 0); final double x, y; - - const ImmutablePoint(this.x, this.y); } diff --git a/examples/misc/lib/language_tour/classes/logger.dart b/examples/misc/lib/language_tour/classes/logger.dart index 2d15f6b862..f96844b937 100644 --- a/examples/misc/lib/language_tour/classes/logger.dart +++ b/examples/misc/lib/language_tour/classes/logger.dart @@ -1,12 +1,5 @@ // #docregion class Logger { - final String name; - bool mute = false; - - // _cache is library-private, thanks to - // the _ in front of its name. - static final Map _cache = {}; - factory Logger(String name) { return _cache.putIfAbsent(name, () => Logger._internal(name)); } @@ -17,6 +10,13 @@ class Logger { Logger._internal(this.name); + final String name; + bool mute = false; + + // _cache is library-private, thanks to + // the _ in front of its name. + static final Map _cache = {}; + void log(String msg) { if (!mute) print(msg); } diff --git a/examples/misc/lib/language_tour/classes/point.dart b/examples/misc/lib/language_tour/classes/point.dart index bf2ce7e128..8cce6fb0e7 100644 --- a/examples/misc/lib/language_tour/classes/point.dart +++ b/examples/misc/lib/language_tour/classes/point.dart @@ -8,9 +8,6 @@ const double yOrigin = 0; // #docregion class-with-distanceTo, constructor-initializer class Point { - final double x; - final double y; - // #docregion class-with-distanceTo, named-constructor Point(this.x, this.y); // #enddocregion class-with-distanceTo, named-constructor @@ -39,4 +36,7 @@ class Point { return sqrt(dx * dx + dy * dy); } // #docregion constructor-initializer, named-constructor + + final double x; + final double y; } diff --git a/examples/misc/lib/language_tour/classes/point_alt.dart b/examples/misc/lib/language_tour/classes/point_alt.dart index d9cb09ea53..31f2f723e8 100644 --- a/examples/misc/lib/language_tour/classes/point_alt.dart +++ b/examples/misc/lib/language_tour/classes/point_alt.dart @@ -6,9 +6,6 @@ /// // #docregion idiomatic-constructor class Point { - double x = 0; - double y = 0; - // Generative constructor with initializing formal parameters: Point(this.x, this.y); // #enddocregion idiomatic-constructor @@ -32,4 +29,7 @@ class Point { // #enddocregion initializer-list-with-assert // #docregion idiomatic-constructor + + double x = 0; + double y = 0; } diff --git a/examples/misc/lib/language_tour/classes/point_redirecting.dart b/examples/misc/lib/language_tour/classes/point_redirecting.dart index 9fe2bc0272..9d41e9c1a4 100644 --- a/examples/misc/lib/language_tour/classes/point_redirecting.dart +++ b/examples/misc/lib/language_tour/classes/point_redirecting.dart @@ -1,9 +1,9 @@ class Point { - double x, y; - // The main constructor for this class. Point(this.x, this.y); // Delegates to the main constructor. Point.alongXAxis(double x) : this(x, 0); + + double x, y; } diff --git a/examples/misc/lib/language_tour/classes/point_with_distance_field.dart b/examples/misc/lib/language_tour/classes/point_with_distance_field.dart index 233df0b699..789376ffd1 100644 --- a/examples/misc/lib/language_tour/classes/point_with_distance_field.dart +++ b/examples/misc/lib/language_tour/classes/point_with_distance_field.dart @@ -2,14 +2,14 @@ import 'dart:math'; class Point { - final double x; - final double y; - final double distanceFromOrigin; - Point(double x, double y) : x = x, y = y, distanceFromOrigin = sqrt(x * x + y * y); + + final double x; + final double y; + final double distanceFromOrigin; } void main() { diff --git a/examples/misc/lib/language_tour/classes/super_initializer_parameters.dart b/examples/misc/lib/language_tour/classes/super_initializer_parameters.dart index 42c3c311e0..4444d0b475 100644 --- a/examples/misc/lib/language_tour/classes/super_initializer_parameters.dart +++ b/examples/misc/lib/language_tour/classes/super_initializer_parameters.dart @@ -1,29 +1,26 @@ // #docregion positional, named class Vector2d { - // #enddocregion positional - // ... - - // #enddocregion named // #docregion positional - final double x; - final double y; - Vector2d(this.x, this.y); // #enddocregion positional // #docregion named Vector2d.named({required this.x, required this.y}); -// #docregion positional -} + // #enddocregion named -class Vector3d extends Vector2d { + // #docregion positional, named // #enddocregion positional // ... // #enddocregion named // #docregion positional - final double z; + final double x; + final double y; +// #docregion positional +} +class Vector3d extends Vector2d { + // #docregion positional // Forward the x and y parameters to the default super constructor like: // Vector3d(final double x, final double y, this.z) : super(x, y); Vector3d(super.x, super.y, this.z); @@ -34,6 +31,14 @@ class Vector3d extends Vector2d { // Vector3d.yzPlane({required double y, required this.z}) // : super.named(x: 0, y: y); Vector3d.yzPlane({required super.y, required this.z}) : super.named(x: 0); + // #enddocregion named + + // #enddocregion positional + // ... + + // #enddocregion named + // #docregion positional + final double z; // #docregion positional } // #enddocregion positional, named diff --git a/src/language/constructors.md b/src/language/constructors.md index 02f457441b..229ab9a026 100644 --- a/src/language/constructors.md +++ b/src/language/constructors.md @@ -23,11 +23,11 @@ to instantiate any instance variables, if necessary: ```dart class Point { - double x = 0; - double y = 0; - // Generative constructor with initializing formal parameters: Point(this.x, this.y); + + double x = 0; + double y = 0; } ``` @@ -53,12 +53,12 @@ which both must be initialized or provided a default value: ```dart class Point { - final double x; - final double y; - Point(this.x, this.y); // Sets the x and y instance variables // before the constructor body runs. + + final double x; + final double y; } ``` @@ -97,15 +97,15 @@ const double xOrigin = 0; const double yOrigin = 0; class Point { - final double x; - final double y; - Point(this.x, this.y); // Named constructor [!Point.origin()!] : x = xOrigin, y = yOrigin; + + final double x; + final double y; } {% endprettify %} @@ -139,11 +139,11 @@ constructor for its superclass, Person. Click **Run** to execute the code. ```dart:run-dartpad:height-450px:ga_id-non_default_superclass_constructor class Person { - String? firstName; - Person.fromJson(Map data) { print('in Person'); } + + String? firstName; } class Employee extends Person { @@ -194,18 +194,18 @@ Super-initializer parameters have similar syntax and semantics to ```dart class Vector2d { + Vector2d(this.x, this.y); + final double x; final double y; - - Vector2d(this.x, this.y); } class Vector3d extends Vector2d { - final double z; - // Forward the x and y parameters to the default super constructor like: // Vector3d(final double x, final double y, this.z) : super(x, y); Vector3d(super.x, super.y, this.z); + + final double z; } ``` @@ -278,14 +278,14 @@ the code. import 'dart:math'; class Point { - final double x; - final double y; - final double distanceFromOrigin; - Point(double x, double y) : x = x, y = y, distanceFromOrigin = sqrt(x * x + y * y); + + final double x; + final double y; + final double distanceFromOrigin; } void main() { @@ -306,13 +306,13 @@ appearing after a colon (:). ```dart class Point { - double x, y; - // The main constructor for this class. Point(this.x, this.y); // Delegates to the main constructor. Point.alongXAxis(double x) : this(x, 0); + + double x, y; } ``` @@ -326,11 +326,11 @@ and make sure that all instance variables are `final`. ```dart class ImmutablePoint { + const ImmutablePoint(this.x, this.y); + static const ImmutablePoint origin = ImmutablePoint(0, 0); final double x, y; - - const ImmutablePoint(this.x, this.y); } ``` @@ -362,13 +362,6 @@ initializes a final variable from a JSON object. ```dart class Logger { - final String name; - bool mute = false; - - // _cache is library-private, thanks to - // the _ in front of its name. - static final Map _cache = {}; - factory Logger(String name) { return _cache.putIfAbsent(name, () => Logger._internal(name)); } @@ -379,6 +372,13 @@ class Logger { Logger._internal(this.name); + final String name; + bool mute = false; + + // _cache is library-private, thanks to + // the _ in front of its name. + static final Map _cache = {}; + void log(String msg) { if (!mute) print(msg); }