Split OOP tutorial chapter and improve progressive disclosure - #7506
Split OOP tutorial chapter and improve progressive disclosure#7506conooi wants to merge 4 commits into
Conversation
There was a problem hiding this comment.
Code Review
This pull request restructures the Dart CLI tutorial by splitting the Object-Oriented Programming chapter into two distinct lessons: "Define classes and objects" and "Structure apps with inheritance and abstract classes". This change involves updating prerequisite chapter references across multiple tutorial files, adding a new quiz for inheritance, and updating navigation files. The review feedback highlights several performance and idiomatic improvements in the newly added code blocks, such as avoiding redundant set allocations in getters by using Set or Iterable directly, and removing the unnecessary async keyword from synchronous methods returning FutureOr.
| final List<Option> _options = []; | ||
|
|
||
| UnmodifiableSetView<Option> get options => | ||
| UnmodifiableSetView(_options.toSet()); |
There was a problem hiding this comment.
Defining _options as a List and then converting it to a Set via _options.toSet() on every access of the options getter is inefficient because it allocates a new Set and a new UnmodifiableSetView every time the getter is read. Additionally, it loses the order of options if they are converted to a standard unordered set.
Instead, define _options as a Set<Option> internally. This naturally prevents duplicate options from being added to the same command, and allows wrapping it directly in UnmodifiableSetView without copying or reallocating on every read.
| final List<Option> _options = []; | |
| UnmodifiableSetView<Option> get options => | |
| UnmodifiableSetView(_options.toSet()); | |
| final Set<Option> _options = {}; | |
| UnmodifiableSetView<Option> get options => | |
| UnmodifiableSetView(_options); |
| UnmodifiableSetView<Command> get commands => | ||
| UnmodifiableSetView<Command>(<Command>{..._commands.values}); |
There was a problem hiding this comment.
Exposing commands by creating a new Set and wrapping it in UnmodifiableSetView on every getter access is inefficient because it performs a copy-on-read. Since the caller only needs to iterate over the commands (e.g., in the HelpCommand loop), it is much simpler and more efficient to expose them as an Iterable<Command> directly from the map's values. This avoids any extra allocations or imports.
| UnmodifiableSetView<Command> get commands => | |
| UnmodifiableSetView<Command>(<Command>{..._commands.values}); | |
| Iterable<Command> get commands => _commands.values; |
| FutureOr<Object?> run(ArgResults args) async { | ||
| var usage = runner.usage; | ||
| for (var command in runner.commands) { | ||
| usage += '\n ${command.usage}'; | ||
| } | ||
|
|
||
| return usage; | ||
| } | ||
| } |
There was a problem hiding this comment.
The run method is marked as async but does not use the await keyword anywhere in its body. Since the method returns FutureOr<Object?>, it can return the computed string synchronously without the overhead of wrapping it in a Future and scheduling it on the event loop. Removing the async keyword is more efficient and idiomatic.
| FutureOr<Object?> run(ArgResults args) async { | |
| var usage = runner.usage; | |
| for (var command in runner.commands) { | |
| usage += '\n ${command.usage}'; | |
| } | |
| return usage; | |
| } | |
| } | |
| @override | |
| FutureOr<Object?> run(ArgResults args) { | |
| var usage = runner.usage; | |
| for (var command in runner.commands) { | |
| usage += '\n ${command.usage}'; | |
| } | |
| return usage; | |
| } |
|
Visit the preview URL for this PR (updated for commit a0c3134): |
Summary
Resolves cognitive overload and uneven pacing in the tutorial's OOP content by splitting the monolithic OOP chapter into two progressive lessons and deconstructing complex classes into incremental steps.
Changes
extends,@override, and command execution.OptionandCommandstep-by-step; explains Dart features like implicit getters satisfying abstract getters,late,UnmodifiableSetView, and records.tutorial.yml,getStarted.yml), separated quizzes, and renumbered downstream chapter prerequisites (Chapters 7–13).dart analyze(0 issues) anddart run.Fixes #7333
Fixes #7418