Skip to content

Commit 6ba4cf0

Browse files
josevalimJosé Valim
authored andcommitted
Update Writing Documentation.md (#8599)
Signed-off-by: José Valim <[email protected]>
1 parent 3eeded0 commit 6ba4cf0

File tree

1 file changed

+32
-20
lines changed

1 file changed

+32
-20
lines changed

lib/elixir/pages/Writing Documentation.md

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Documentation in Elixir is usually attached to module attributes. Let's see an e
1717
@moduledoc """
1818
This is the Hello module.
1919
"""
20+
@moduledoc since: "1.0.0"
2021

2122
@doc """
2223
Says hello to the given `name`.
@@ -29,12 +30,13 @@ Documentation in Elixir is usually attached to module attributes. Let's see an e
2930
:ok
3031

3132
"""
33+
@doc since: "1.3.0"
3234
def world(name) do
3335
IO.puts "hello #{name}"
3436
end
3537
end
3638

37-
The `@moduledoc` attribute is used to add documentation to the module. `@doc` is used before a function to provide documentation for it. Besides the attributes above, `@typedoc` can also be used to attach documentation to types defined as part of typespecs.
39+
The `@moduledoc` attribute is used to add documentation to the module. `@doc` is used before a function to provide documentation for it. Besides the attributes above, `@typedoc` can also be used to attach documentation to types defined as part of typespecs. Elixir also allows metadata to be attached to documentation, by passing a keyword list to `@doc` and friends.
3840

3941
## Function Arguments
4042

@@ -51,6 +53,20 @@ The compiler will infer this argument as `map`. Sometimes the inference will be
5153
size
5254
end
5355

56+
## Documentation metadata
57+
58+
Elixir allows developers to attach arbitrary metadata to the documentation. This is done by passing a keyword list to the relevant attribute (such as `@moduledoc`, `@typedoc`, and `@doc`). A commonly used metadata is `:since`, which annotates in which version that particular module, function, type, or callback was added, as shown in the example above.
59+
60+
Another common metadata is `:deprecated`, which emits a warning in the documentation, explaining that its usage is discouraged:
61+
62+
@doc deprecated: "Use Foo.bar/2 instead"
63+
64+
Note the `:deprecated` key does not warn when a developer invokes the functions. If you want the code to also emit a warning, you can use the `@deprecated` attribute:
65+
66+
@deprecated "Use Foo.bar/2 instead"
67+
68+
Metadata can have any key. Documentation tools often use metadata to provide more data to readers and to enrich the user experience.
69+
5470
## Recommendations
5571

5672
When writing documentation:
@@ -59,7 +75,7 @@ When writing documentation:
5975

6076
* Reference modules by their full name.
6177

62-
Markdown uses backticks (`` ` ``) to quote code. Elixir builds on top of that to automatically generate links when module or function names are referenced. For this reason, always use full module names. If you have a module called `MyApp.Hello`, always reference it as `` `MyApp.Hello` `` and never as `` `Hello` ``.
78+
Markdown uses backticks (`` ` ``) to quote code. Elixir builds on top of that to automatically generate links when module or function names are referenced. For this reason, always use full module names. If you have a module called `MyApp.Hello`, always reference it as `` `MyApp.Hello` `` and never as `` `Hello` ``.
6379

6480
* Reference functions by name and arity if they are local, as in `` `world/1` ``, or by module, name and arity if pointing to an external module: `` `MyApp.Hello.world/1` ``.
6581

@@ -70,26 +86,35 @@ When writing documentation:
7086
* Start new sections with second level Markdown headers `##`. First level headers are reserved for module and function names.
7187

7288
* Place documentation before the first clause of multi-clause functions. Documentation is always per function and arity and not per clause.
89+
90+
* Use the `:since` key in the documentation metadata to annotate whenever new functions or modules are added to your API.
7391

7492
## Doctests
7593

7694
We recommend that developers include examples in their documentation, often under their own `## Examples` heading. To ensure examples do not get out of date, Elixir's test framework (ExUnit) provides a feature called doctests that allows developers to test the examples in their documentation. Doctests work by parsing out code samples starting with `iex>` from the documentation. You can read more about it at `ExUnit.DocTest`.
7795

7896
Notice doctests have limitations. When you cannot doctest a function, because it relies on state or side-effects, we recommend developers include examples directly without the `iex>` prompt.
7997

80-
## Documentation != Comments
98+
## Documentation != Code comments
99+
100+
Elixir treats documentation and code comments as different concepts. Documentation is an explicit contract between you and users of your Application Programming Interface (API), be them third-party developers, co-workers, or your future self. Modules and functions must always be documented if they are part of your API.
81101

82-
Elixir treats documentation and code comments as different concepts. Documentation is for users of your Application Programming Interface (API), be it your co-worker or your future self. Modules and functions must always be documented if they are part of your API.
102+
Code comments are aimed at developers reading the code. They are useful for marking improvements, leaving notes (for example, why you had to resort to a workaround due to a bug in a library), and so forth. They are tied to the source code: you can completely rewrite a function and remove all existing code comments, and it will continue to behave the same, with no change to either its behaviour or its documentation.
83103

84-
Code comments are for developers reading the code. They are useful to mark improvements, leave notes for developers reading the code (for example, you decided not to call a function due to a bug in a library) and so forth.
104+
Because private functions cannot be accessed externally, Elixir will warn if a private function has a `@doc` attribute and will discard its content. However, you can add code comments to private functions, as with any other piece of code, and we recommend developers to do so whenever they believe it will add relevant information to the readers and maintainers of such code.
85105

86-
In other words: documentation is required, code comments are optional.
106+
Finally, beware of redundant code comments, such as the ones describing the exact same that the code does:
107+
108+
# Total is the sum of the batch and individual entries
109+
total = batch_sum + individual_sum
110+
111+
In summary, documentation is a contract with users of your API, who may not necessarily have access to the source code; whereas code comments are for those who interact directly with the source. You can learn and express different guarantees about your software by separating those two concepts.
87112

88113
## Hiding Internal Modules and Functions
89114

90115
Besides the modules and functions libraries provide as part of their public interface, libraries may also implement important functionality that is not part of their API. While these modules and functions can be accessed, they are meant to be internal to the library and thus should not have documentation for end users.
91116

92-
Luckily, Elixir allows developers to hide modules and functions from the documentation. For example, one common practice for documenting internal behaviour is to set the `@moduledoc` attribute to `false` while documenting each function:
117+
Conveniently, Elixir allows developers to hide modules and functions from the documentation, by setting `@doc false` to hide a particular function, or `@moduledoc false` to hide the whole module. If a module is hidden, you may even document the functions in the module, but the module itself won't be listed in the documentation:
93118

94119
defmodule MyApp.Hidden do
95120
@moduledoc false
@@ -102,25 +127,12 @@ Luckily, Elixir allows developers to hide modules and functions from the documen
102127
end
103128
end
104129

105-
Similarly, developers can add `@doc false` to functions they do not want to be publicly exposed:
106-
107-
defmodule MyApp.Sample do
108-
@doc false
109-
def add(a, b), do: a + b
110-
end
111-
112130
However, keep in mind that adding `@doc false` does not make the function private. The function above can still be invoked as `MyApp.Sample.add(1, 2)`. Not only that, if `MyApp.Sample` is imported, the `add/2` function will also be imported into the caller. For those reasons, be cautious when adding `@doc false` to functions, instead use one of these two options:
113131

114132
* Move the undocumented function to a module with `@moduledoc false`, like `MyApp.Hidden`, ensuring the function won't be accidentally exposed or imported. Remember you can use `@moduledoc false` to hide a whole module and still document each function with `@doc`. Tools will still ignore the module.
115133

116134
* Start the function name with one or two underscores, for example, `__add__/2`, and add `@doc false`. The compiler does not import functions with leading underscores and they hint to anyone reading the code of their intended private usage.
117135

118-
## Documenting Private Functions
119-
120-
Elixir warns if a private function has a `@doc` attribute and discards its content, because `@doc` is intended to be used only for your public interface.
121-
122-
Private functions may still need internal documentation for maintainers, though. That can be accomplished with code comments.
123-
124136
## Code.fetch_docs/1
125137

126138
Elixir stores documentation inside pre-defined chunks in the bytecode. It can be accessed from Elixir by using the `Code.fetch_docs/1` function. This also means documentation is only accessed when required and not when modules are loaded by the Virtual Machine. The only downside is that modules defined in-memory, like the ones defined in IEx, cannot have their documentation accessed as they do not have their bytecode written to disk.

0 commit comments

Comments
 (0)