-
Notifications
You must be signed in to change notification settings - Fork 125
Add chips to class pages for class modifiers #3401
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,12 +4,33 @@ | |
|
||
import 'package:dartdoc/src/render/language_feature_renderer.dart'; | ||
|
||
const Map<String, String> _featureDescriptions = {}; | ||
|
||
const Map<String, String> _featureUrls = {}; | ||
|
||
/// An abstraction for a language feature; used to render tags to notify | ||
/// the user that the documentation should be specially interpreted. | ||
const Map<String, String> _featureDescriptions = { | ||
'sealed': 'All direct subtypes must be defined in the same library.', | ||
'abstract': 'This type can not be directly constructed.', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think "can not be directly constructed" is the most relevant bit here for users. Maybe "This class may have abstract members and cannot be directly constructed"? |
||
'base': 'This type can only be extended (not implemented or mixed in).', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "... outside of the library in which it is declared"? Maybe it's better to be wrong but concise? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure our language team friends would have phrased it like that, but yes, this shorter version is what I was told was going to be advertised. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably in this context, better to say "This class can..." here, and in each of the ones below? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
'interface': 'This type can only be implemented (not extended or mixed in).', | ||
'final': 'This type can neither be extended, implemented, nor mixed in.', | ||
'mixin': 'This type can be used as a class and a mixin.', | ||
}; | ||
|
||
const Map<String, String> _featureUrls = { | ||
// TODO(jcollins-g): link to dart.dev for all links once documentation is | ||
// available. | ||
'sealed': | ||
'https://github.com/dart-lang/language/blob/main/accepted/future-releases/sealed-types/feature-specification.md#sealed-types', | ||
'abstract': 'https://dart.dev/language/classes#abstract-classes', | ||
'base': | ||
'https://github.com/dart-lang/language/blob/main/accepted/future-releases/class-modifiers/feature-specification.md#class-modifiers', | ||
'interface': | ||
'https://github.com/dart-lang/language/blob/main/accepted/future-releases/class-modifiers/feature-specification.md#class-modifiers', | ||
'final': | ||
'https://github.com/dart-lang/language/blob/main/accepted/future-releases/class-modifiers/feature-specification.md#class-modifiers', | ||
'mixin': | ||
'https://github.com/dart-lang/language/blob/main/accepted/future-releases/class-modifiers/feature-specification.md#class-modifiers', | ||
}; | ||
|
||
/// An abstraction for a language feature; used to render tags ('chips') to | ||
/// notify the user that the documentation should be specially interpreted. | ||
class LanguageFeature { | ||
/// The description of this language feature. | ||
String? get featureDescription => _featureDescriptions[name]; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe "The subtypes of this class will be checked for exhaustiveness in switches"? I'm assuming these need to be brief and self contains, and sealed means quite a bit: it really means "This class is abstract and all direct subtypes must be defined in the same library. Switches over the direct subtypes of this class will be checked for exhaustiveness". But that's probably too much for this? So barring that, I think exhaustiveness is the important bit for users.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The exhaustiveness bit is the most important part for authors of a class, but for users of a class wanting to know its API surface, the exhaustiveness checking it does internally is actually irrelevant AFAIK? Still, maybe making sure people know how to use
sealed
properly is so important that it trumps describing what's actually visible on the API surface. I'll put this new wording in for now and see how it lands with people.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not 100% sure what qualifies as API surface here so I'm not sure quite how to classify this. Most class modifiers primarily affect what another class author can do with a class. That is,
final
says "other class authors are forbidden from extending or implementing this class". But it doesn't affect anything about how non-class authors use the class (that is, it does not affect the API of instances of this class at all). Thesealed
modifier affects both class-authors and non class-authors. That is, a class author might want to know that a sealed class can't be extended or implemented (outside of its library). But a non class-author will definitely want to know that "this class is intended to be the type of a closed family (an algebraic datatype), and hence it is likely intended to be switched over, and I will get exhaustiveness checking if I do so". Ideally, we'd surface both, but if we surface only one I believe it should be the latter. My reasoning is that if what you care about is "can't be subclassed or implemented outside of the library" just use final. It's every bit as good. The only reason to usesealed
is that you want to provide clients of your API with exhaustiveness checking. And therefore, I'd argue that that is the most important thing to surface.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TL;DR: This sounds reasonable, I agree. If you care, see below for where I was coming from originally.
An extremely broad definition of the API surface of a class (or any declaration) is : What can I do with this class, using the Dart language, that does not require modifying the class itself? So that includes (indirectly) instances as well as class authors, as well as people modifying the library the class is contained in. It's been my belief that in an ideal universe, API documentation should make it clear what can be done with a thing without having to read its source code.
A more (IMHO, mileage may vary) useful, limited definition that covers most cases where people are looking at documentation of something: What can I do with this class that does not involve modifying the class itself or the library (or even, package) it came from? This includes instances as well as class authors like the above, but excludes the case where (for example) a Flutter application developer might be looking to modify Flutter itself to solve a problem. I figure, most of the time a Flutter application developer is not looking to modify Flutter itself as part of their app development but does want to know the behavior of Flutter classes, methods, and so on.
It was this second definition that led me to think that the other aspect of sealed (that it can not be subclassed or implemented outside of the library) was more important in API documentation. But your point about
final
makes a lot of sense to me. Since the major differences betweensealed
andfinal
only make sense within the library itself, we probably should highlight that difference. So I'm now in agreement that your suggestion is best.