-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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: go/doc: add support for sections #44447
Comments
I am confused about what is being proposed here exactly. |
This might help with #44301. |
Adding to minutes. |
On hold for #45533. |
Placed on hold. |
This is a stray thought, but it seems to me that the issue may be broader than documentation. At the moment, a package is both a unit of import and a namespace. A package more or less needs to be a namespace, but it would sometimes be useful for it to have sub-namespaces. As an example drawn from something I'm playing with, the package "color" might usefully have name spaces
If this were true, then it would become natural for godoc to organize documentation by namespace. Though it could have been thought out better, Issue #20467 proposed something along these lines, and was rejected by @ianlancetaylor, who said that Go prefers to decompose concepts rather than nest them, and said words to the effect that replacing One can divide packages into package hierarchies, but within commonly related sub-concepts this often leads to circular package import dependencies, while sub-namespaces within a package can be viewed as simultaneously co-defined and tolerant of circular reference. A sub-namespace is syntactic sugar. It's value lies in organizing the names for human consumption, which is an important criteria in programming language design. What I am trying to express, I think, is that there seems to be a disconnect between human organization patterns and code organization patterns. Go's sparsity is something I admire, but there seem to be areas where Go has initially rejected approaches whose value has been well established in other contexts. While doxygen has serious flaws and a dubiously ambiguous specification, it also provides critical and useful expressiveness that seems to be creeping glacially into godoc one feature at a time. This feels somewhat similar. |
We have headings now, so I'm not sure there is anything to do here. dsnet, is there something that should still be added? Thanks. |
The main utility of sections isn't the ability to provide headings, but rather a way for the package author to explicitly group related Go declarations together. |
Ah, thanks, I misunderstood the proposal. |
(This is a re-proposal of #18342)
Table of Contents
go/doc
packagego doc
toolpkg.go.dev
websiteProblem Statement
The Go ecosystem has a set of tools broadly called "godoc" that produces humanly readable documentation for Go packages. Today, godoc implementations typically render all global declarations for constants, variables, functions, methods, and types in sorted order. While, there is some effort to correlate related declarations (e.g., a function that looks like a constructor with the type it produces, and methods with the receiver type), this minimal amount of grouping is often insufficient to adequately explain the functionality of a package at a quick glance.
Many other programming languages allow nesting of declarations (e.g., by declaring a class within another class, a static function within a class, or creating a namespace). These declarations provide other languages the ability to express a form a grouping with finer granularity that their respective godoc-like tool can make use of. Go has no such nesting mechanism, and so there is no language-specific way to express the grouping of related functionality.
The inability to specify grouping of functionality leads to godoc pages that are relatively unreadable. We do not propose changing the Go language in any way, but do propose that godoc provide support for user-defined sections for documentation purposes. This would allow package authors to group declarations that are related in functionality and to control the ordering of the sections themselves.
See the Examples below for how some packages become more readable with the use of sections.
Proposed Solution
Code is often written in a way where declarations that would be grouped together under a section for documentation is already located in proximity to each other within the source code itself. We propose that a special
Section:
marker in a top-level comment be used to signify the start of a section. Allconst
,var
,func
, andtype
declarations below that marker will be considered part of that section.The scope of a section extends until either:
Section:
marker.The section marker syntax is designed to be lightweight and read naturally in source code. The syntax provides for a required heading and an optional description. For example:
The heading is a string that immediately follows the
Section:
marker and must be one line. The description is optional and comprises of zero or more paragraphs (similar to package documentation) and must be preceded by a blank line. A godoc implementation may create an HTML anchor for the section heading. Thus, it is discouraged that authors change the heading lest they potentially break URLs to their sections on godoc. Note that this is already the case for "heading" lines supported by godoc today.Sections with the exact same heading are treated as the same section. If multiple sections with the same heading each have a description, then the resulting section description in godoc will contain the concatenation of all paragraphs from each section (in the order they appear in the file and according to the lexicographical sorting of the source files). This practice is discouraged, but matches the behavior of when multiple source files each possess a package description (also discouraged practice).
When rendering a godoc page, declarations that do not fall under any explicit section are listed first, followed by all sections ordered lexicographically by the heading. There is no support for sub-sections, which can be accomplished by prefixing the heading with a section number to enforce a specific ordering (e.g.,
Section: 1. Main section
,Section: 1.1. Sub-section
,Section: 1.2. Sub-section
, etc.).Changes to the
go/doc
packageMost godoc implementations rely on the
go/doc
package to collect source code documentation from the Go AST for a given package. Adding support for sections to this package allows different godoc implementations to share logic for how to identify each section and only leaves each implementation responsible for how they decide to render the sections (or not).These are the proposed changes to the
doc
package's external API:The
Package
type has a newSections
field which is a list of all sections found in the package, sorted according to the section heading. For backwards compatibility, theConsts
,Types
,Vars
,Funcs
, andExamples
fields remain unaffected by the presence of sections (lest the use of sections cause declarations to mysteriously disappear on godoc implementations that don't support sections).The
Value
,Type
,Func
, andExample
types each have a newSection
field which is a pointer to the section that the declaration belongs to (or nil if it doesn't fall under any section).The
Section
type is new and contains the required heading (in theHeading
field) and the optional description (in theDoc
field). Similar to thePackage
type, it contains a list ofConsts
,Types
,Vars
,Funcs
, andExamples
that belong within that section.Changes to the
go doc
toolThe
go doc
tool is the primary way users view Go documentation on the command line. The implementation would be modified to make use of the new features provided by thego/doc
package. The only effect of sections would be when the user prints documentation for the entire package. All other features ofgo doc
would remain unchanged. Since thego doc
tool and thego/doc
package are released together, the tool can make use of the new package features in the same release.Changes to the
pkg.go.dev
websiteThe pkg.go.dev website is increasingly becoming the de-facto portal to view Go documentation for modules and packages. We propose that the site be updated to support sections. It is unclear whether the backend implementation would wait until a release of the Go toolchain with the relevant
go/doc
package changes, or whether the implementation would vendor a pre-release version of the package.Examples
encoding/binary
This shows how even small packages benefits from sections. In this situation, the
ByteOrder
type serves as documentation for what methods exist on the types for theLittleEndian
andBigEndian
variables. Unfortunately, the default ordering of godoc places these related declarations on opposite sides of godoc page, which greatly diminishes the clarity thatByteOrder
,LittleEndian
, andBigEndian
are related. It is notable that these declarations are all co-located together in the source code.google.golang.org/protobuf/proto
This is a recently released package, which had the opportunity to choose the best portions from the older
proto
package. Even though it avoids the cruft of the oldproto
package that grew organically over time, the newproto
package can still benefit significantly from sections.The lexicographical sorting of declarations does not make it clear what the primary functionality is and how they relate to one another.
Size
,Marshal
, andUnmarshal
functions are the primary serialization functionality and should appear together early on.Clone
,Merge
,Equal
,Reset
, andCheckInitialized
functions are auxiliary functionality that should occur afterMarshal
andUnmarshal
. Note that the default grouping of godoc unfortunately placesClone
as a constructor ofMessage
, when it is better grouped withMerge
.Bool
,Int32
,Int64
,Uint32
,Uint64
,Float32
,Float64
, andString
are constructors for optional scalar types. Due to the lexicographical sorting of declarations, these are unfortunately interspersed among the other function declarations, greatly hindering readability.HasExtension
,GetExtension
,SetExtension
,ClearExtension
, andRangeExtensions
function are related to proto2 extensions. Due to the different prefix, these are also unfortunately interspersed among the other function declarations. I was tempted to swap the prefix and suffix (e.g.,ExtensionHas
,ExtensionGet
, etc.) so that the functions appear together in godoc. Authors really shouldn't have to play such word games.For all the above groupings of declarations, they are all already co-located together in the source-code. This gives further evidence that documentation sections that best describe a package very often matches the implementation.
Related proposals
#25444: add support for hotlinks
When "sections" was first proposed in 2016, Russ counter-proposed with the idea of automatically turning exported names into links, which was subsequently accepted. I built a few prototypes for that feature, but never integrated it into godoc since the godoc ecosystem at the time was too fractured (i.e., needing to implement the same logic in multiple different godoc implementations) and also because modules did not exist (which is necessary to improve the accuracy of hotlinks).
In the years since, I've become increasingly convinced that "hotlinks" is troublesome:
False positives:
IP
occurs, is the referent theIP
Go type or the IP protocol suite? While related, they are still fairly different things: the former represents just an IPv4 address, while the latter refers to an entire protocol suite.Things
and there is noThings
declaration because the author is referring to a collection ofThing
objects. In some cases a package might even have bothThing
andThings
declared. However, depending on the context, the wordThings
may sometimes refer to a collection of individualThing
objects or a singleThings
object. Hotlinking is unable to distinguish between this case. This is further complicated by English grammar rules not consistently adding an "s" suffix for plural forms, but has many exceptions (e.g., plural form ofTomato
isTomatoes
).Buffer.Read
, it may simply reference the wordWrite
, with the implicit assumption thatWrite
references theBuffer.Write
method and not some top-levelWrite
function. Alternatively, the author may really have wanted it to reference the top-levelWrite
function. The reference is ambiguous from the name alone, but context in the sentence often makes it clear to humans which is intended. In some cases, references to both aWrite
function and aWrite
method may occur together when the documentation tries to explain which to use in a given situation.False negatives:
Pipe.Read
) and fields in a struct (e.g.,Header.Name
). However, most godoc implementations do not have the full type information available, and so may not have knowledge about certain possible references (e.g., a method or field promoted by embedding a type from another package). An example situation is embeddingio.Reader
in an interface declaration and referring to theRead
method in the documentation. Even embedding of a type from the same package is challenging since it requires partially implementing portions of the Go type system in godoc.io.EOF
should be linked to theio.EOF
variable. One heuristic to detect such cases is if the identifier which looks like a package (e.g.,io
) happens to be imported by the current package and also if that package really does have that declaration (e.g.,EOF
in theio
package). However, implementing this would require the ability to lookup a declaration in a different package. The existence of modules makes this possible, but it will be difficult for thego/doc
package to provide this feature without substantial changes to its API and implementation.In summary, I believe hotlinking goes against the philosophy of Go that "clear is better than clever". Hotlinking is very clever, but it cannot provide the right results all the time and in some cases may even actively mislead users. It is built on a set of heuristics (not rules) which may change over time, which further leads to a poor user experience where a godoc page is rendered as intended today, but renders differently (and maybe incorrectly) in the future due to changes to the hotlinking heuristics. Lastly, it incurs too much mental burden on package authors to think about whether a "exported" word they write will be hotlinked correctly or not. On the other hand, sections are simple, explicit, clear, and stable (relative to changes to godoc).
The text was updated successfully, but these errors were encountered: