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

Re-land #52859: Revamp the engine style guide, remove always_specify_types #53223

Merged
merged 2 commits into from
Jun 5, 2024

Conversation

matanlurey
Copy link
Contributor

Based on the (internal) discussion around converging on using the official Dart style guide, the design discussion https://flutter.dev/go/use-dart-style-in-flutter-engine, and with the exception of the code that gets published under dart:ui (as that is user-facing, and we'd like to evolve the code style in conjunction with the framework), we're going to be (gradually) adopting the Dart style guide in flutter/engine.

For now, we:

  • Remove always_specify_types (except for lib/ui, i.e. dart:ui)
  • Re-enable type_annotate_public_apis (which is now relevant since the above is disabled)
  • Announce our intent to re-format and apply the Dart formatter (which we'll land in the near future)

I also took the opportunity to specify more about our style guide use in general, mostly to make it easier to understand our conventions, and also call out known problem areas (notably, our over-use of shared_ptr and auto in some cases). I am happy to split those up, but it was easier to make the markdown changes at once.

I also took @cbracken and folks advice and clarified directly that explicit types in Dart are not bad (with examples).

Copy link
Contributor

@jtmcdole jtmcdole left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@matanlurey matanlurey added the autosubmit Merge PR when tree becomes green via auto submit App label Jun 5, 2024
Copy link
Contributor

@eyebrowsoffire eyebrowsoffire left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few drive-by suggestions.

CONTRIBUTING.md Outdated

```dart
// Without 'num', the map would be inferred as 'Map<String, int>'.
const Map<String, num> map = {'one': 1, 'two': 2, 'three': 3};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you mentioned you wanted to move the types to the right hand side here in this example? i.e.

const map = <String, num>{'one': 1, 'two': 2, 'three': 3};

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, ezpz.

```dart
// When variables are in the same scope, reduce() clearly returns an int.
var list = [1, 2, 3];
var sum = list.reduce((a, b) => a + b);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this example, I think @stuartmorgan had feedback at the meeting that the judgment of how much context is needed should be made on individual lines in isolation. That way, if in a subsequent change, the lines of code end up getting inserted between these two lines, we don't end up with a line who is too separated from that context. I think that's a pretty reasonable guideline personally, so I would be in favor of changing this example and perhaps even explicitly mentioning the rule of thumb Stuart suggested.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can rely on reviewers and drive-by code improvements to enforce these more subtle issues?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah to be clear, I hear the issue, I think it's worth thinking about. I don't think there is a specific line count I can suggest, some folks will think 10 lines are OK, others will balk at 4 lines.

Let's try this as-is, and if there are real issues that result of not having stricter guidance we can revisit.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I double-checked the C++ guide later, and I was wrong about auto guidance being line-level. It just says (for local variables) to only use it "to make the code clearer by eliminating type information that is obvious or irrelevant". What is "obvious" is entirely left to discretion.

@matanlurey matanlurey removed the autosubmit Merge PR when tree becomes green via auto submit App label Jun 5, 2024
@matanlurey matanlurey added the autosubmit Merge PR when tree becomes green via auto submit App label Jun 5, 2024
@auto-submit auto-submit bot merged commit c7667fd into flutter:main Jun 5, 2024
29 checks passed
Copy link
Member

@cbracken cbracken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One more lgtm for posterity.

LGTM stamp from a Japanese personal seal

@matanlurey matanlurey deleted the reland-52859 branch June 5, 2024 16:59
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 5, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 5, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 5, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jun 5, 2024
auto-submit bot pushed a commit to flutter/flutter that referenced this pull request Jun 5, 2024
…149770)

flutter/engine@11a32d4...f377330

2024-06-05 skia-flutter-autoroll@skia.org Roll Skia from 37755d48cca3 to 8448abc95867 (7 revisions) (flutter/engine#53230)
2024-06-05 skia-flutter-autoroll@skia.org Roll Dart SDK from dac7c04c7342 to f838a9a8d45f (3 revisions) (flutter/engine#53225)
2024-06-05 skia-flutter-autoroll@skia.org Roll Skia from 337c3c4d1f1b to 37755d48cca3 (45 revisions) (flutter/engine#53224)
2024-06-05 yjbanov@google.com [web] enable always_specify_types for web_ui (flutter/engine#53226)
2024-06-05 matanlurey@users.noreply.github.com Re-land #52859: Revamp the engine style guide, remove `always_specify_types` (flutter/engine#53223)
2024-06-05 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from pagJoGS4kQ8Efa_if... to 2xWubo2mRP_2_wXKJ... (flutter/engine#53222)
2024-06-05 fmil@google.com [icu] Manual roll of icu (flutter/engine#53199)
2024-06-05 98614782+auto-submit[bot]@users.noreply.github.com Reverts "[ios][platform_view] Use CAShapeLayer as the mask to avoid software rendering  (#53072)" (flutter/engine#53220)
2024-06-05 41930132+hellohuanlin@users.noreply.github.com [ios][platform_view] Use CAShapeLayer as the mask to avoid software rendering  (flutter/engine#53072)
2024-06-05 skia-flutter-autoroll@skia.org Roll Dart SDK from 343c20614708 to dac7c04c7342 (1 revision) (flutter/engine#53209)
2024-06-04 jonahwilliams@google.com [Impeller] Intel iOS Simulators must block on GPU completion. (flutter/engine#53073)

Also rolling transitive DEPS:
  fuchsia/sdk/core/linux-amd64 from pagJoGS4kQ8E to 2xWubo2mRP_2

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
Please CC matanl@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human
is aware of the problem.

To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
// Literals (strings, numbers, lists, maps, etc) always return the same type.
var name = 'John Doe';
var flag = true;
var numbers = [1, 2, 3];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(this PR was posted and landed while I was out of town so I didn't have the opportunity to comment on it, so apologies for commenting after it landed)

This particular case ([1, 2, 3]) is one where having types explicitly somewhere (whether lhs or rhs doesn't matter) is actually really important. Consider for example an array [1.1] where one day the 1.1 is changed to 1. Despite this looking like an innocent change, it will change the inferred type.

In general, the int and double literals are not uniquely typed, and so I would always specify the types when number literals are used.

It's especially important because there's actually three types. For example, [1.1, 2] is not a List<double>, it's a List<num>. It's very easy to end up in situations where the exact type is not actually what it seems to "obviously" be, especially when code is being edited (as opposed to first written).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there real-world cases where that change in inferred type both matters, but isn't caught by the compiler?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the most common places for array literals is tests, where often the literals are then compared in type-unsafe ways (e.g. using expect). Not only would the type be not what the developer expects, and not only would the compiler not notice, but the test might even still pass despite the type being "wrong". This can lead to different people reading the code getting different interpretations of what the code intended (especially after multiple people have edited the code), which is exactly the thing we're trying to avoid by having a consistent style.

Explicit types everywhere avoids that in a verbose and brute-force manner. The more nuanced style suggestions here are much less verbose and lead to leaner code, but at the cost of requiring more thought when deciding where to include types or not include types. One example of that is this int/num/double confusion.

var name = 'John Doe';
var flag = true;
var numbers = [1, 2, 3];
var map = {'one': 1, 'two': 2, 'three': 3};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a similar example. Consider {'one': 1.0, 'two': 2.0, 'three': 3.0}. If you add 'four': 4 (which is a valid way of specifying a new value in a Map<String, double>, suddenly the type of the map changes (to Map<String, num>).

var string = foo().toString();

// It's reasonable to assume that length returns an int.
var length = string.length;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whether it's reasonable or not seems pretty subjective. (Also, it's not actually reasonable for "String" to have a "length" member in the first place... what should it return? It's almost never what you want. list.length might be less controversial, though I would still give an explicit int type.)


```dart
// When variables are in the same scope, reduce() clearly returns an int.
var list = [1, 2, 3];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as noted above, the type of this literal is not obvious.

ImageBuffer buffer = fetchLatest();

// What does this large chain of method calls return?
Iterable<int> numbers = foo().bar().map((b) => b.baz());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for these in general I would recommend putting the types on the method calls, so that the type checking happens earlier in the process (e.g. using map<int>). It also avoids having the long Iterable<int> name.


```dart
// Without 'num', the map would be inferred as 'Map<String, int>'.
const map = <String, num>{'one': 1, 'two': 2, 'three': 3};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally we'd never do anything with explicit num types, it has performance implications. I think this example would be just as valid but more realistic if instead of num we said double.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
autosubmit Merge PR when tree becomes green via auto submit App
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants