Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: use "enhanced enums" in the repo for reduced boilerplate #147799

Open
nate-thegrate opened this issue May 3, 2024 · 4 comments
Open
Assignees
Labels
c: proposal A detailed proposal for a change to Flutter framework flutter/packages/flutter repository. See also f: labels. P3 Issues that are less important to the Flutter project team-framework Owned by Framework team triaged-framework Triaged by Framework team

Comments

@nate-thegrate
Copy link
Member

There are a few situations where the same enum logic is implemented over and over again.


A good example would be distinguishing an AnimationStatus between forward/complete and reverse/dismissed.

15 style guide violations (click to collapse)

return status == AnimationStatus.completed || status == AnimationStatus.forward;

return status == AnimationStatus.completed || status == AnimationStatus.forward;

return status == AnimationStatus.completed || status == AnimationStatus.forward;

final bool isOpen = status == AnimationStatus.completed || status == AnimationStatus.forward;

return _controller.status == AnimationStatus.completed ||
_controller.status == AnimationStatus.forward;

return status == AnimationStatus.completed ||
status == AnimationStatus.forward;

if (status == AnimationStatus.completed ||
status == AnimationStatus.forward) {

return status == AnimationStatus.completed ||
status == AnimationStatus.forward;

return status == AnimationStatus.completed ||
status == AnimationStatus.forward;

return animation.status == AnimationStatus.forward
|| animation.status == AnimationStatus.completed;

return animation.status == AnimationStatus.forward || animation.status == AnimationStatus.completed;

_snackBarController!.status == AnimationStatus.forward ||
_snackBarController!.status == AnimationStatus.completed,

widget.animationController.status == AnimationStatus.forward
|| widget.animationController.status == AnimationStatus.completed,

final bool transitioningForwards = _controller.status == AnimationStatus.completed ||
_controller.status == AnimationStatus.forward;

ignoring: animation!.status == AnimationStatus.reverse || // changedInternalState is called when animation.status updates
animation!.status == AnimationStatus.dismissed, // dismissed is possible when doing a manual pop gesture

Rather than refactoring all of these into switch expressions, I think it'd be best to take advantage of enhanced enum features and improve AnimationStatus directly.

@nate-thegrate nate-thegrate added framework flutter/packages/flutter repository. See also f: labels. c: proposal A detailed proposal for a change to Flutter P3 Issues that are less important to the Flutter project team-framework Owned by Framework team triaged-framework Triaged by Framework team labels May 3, 2024
@nate-thegrate nate-thegrate self-assigned this May 3, 2024
@FusoraTech
Copy link

You showed that currently have something like this:

enum AnimationStatus {
  /// The animation is stopped at the beginning.
  dismissed,

  /// The animation is running from beginning to end.
  forward,

  /// The animation is running backwards, from end to beginning.
  reverse,

  /// The animation is stopped at the end.
  completed,
}

final AnimationStatus status = _controller.status;

final bool returnValue = status == AnimationStatus.completed || status == AnimationStatus.forward; 

Would you mind to show the proposed cleaner, simpler and more performant preferred new way that reduces the boilerplate?

@nate-thegrate
Copy link
Member Author

nate-thegrate commented May 4, 2024

@FusoraTech I forgot to link to this issue in the pull request I made, my bad!

I was going to wait to refactor until that PR is approved, but I'd be happy to share some ideas now 🙂


animated_cross_fade.dart

before

bool get _isTransitioning => _controller.status == AnimationStatus.forward || _controller.status == AnimationStatus.reverse;

Widget build(BuildContext context) {
  final bool transitioningForwards = _controller.status == AnimationStatus.completed ||
                                     _controller.status == AnimationStatus.forward;
  if (transitioningForwards) {
    // ...
  }
}

after

bool get _isTransitioning => _controller.isRunning;

Widget build(BuildContext context) {
  if (_controller.aimedForward) {
    // ...
  }
}
  • since _controller.isRunning is so concise, we might be able to factor out the _isTransitioning getter entirely!

@FusoraTech
Copy link

I understand. The idea is to make specialized getters right inside those "smart enums", replacing complex reusable ifs with switches when possible, and reducing the boilerplate replacing those long ifs spread everywhere by those new concise getters.

@FusoraTech
Copy link

Just to be clear, my worry was about exchanging performance in one place by complexity in another place, and performance penalty adding an extra call layer, just to satisfy a code clarity guidance.

auto-submit bot pushed a commit that referenced this issue May 16, 2024
Based on issue #147799, this pull request adds two `AnimationStatus` getters.

```dart
bool get isRunning => switch (this) {
  forward   || reverse   => true,
  completed || dismissed => false,
};

bool get aimedForward => switch (this) {
  forward || completed => true,
  reverse || dismissed => false,
};
```

I also added a `.toggle()` method for animation controllers that makes use of `aimedForward`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c: proposal A detailed proposal for a change to Flutter framework flutter/packages/flutter repository. See also f: labels. P3 Issues that are less important to the Flutter project team-framework Owned by Framework team triaged-framework Triaged by Framework team
Projects
None yet
Development

No branches or pull requests

2 participants