Engee documentation

Documentation

Access to documentation

To access the documentation in the REPL or https://github.com/JuliaLang/IJulia.jl [IJulia] enter ? before the name of the macro or function, and press the Enter key. Examples:

?cos
?@time
?r""

the documentation for the corresponding function, macro, and string macro will be displayed. In most Julia environments, there is a way to access the documentation directly.

  • https://www.julia-vscode.org /[VS Code] displays the documentation when the mouse pointer hovers over the function name. You can also search through the documentation in the Julia sidebar.

  • In the environment https://github.com/fonsp/Pluto.jl [Pluto] you can open the Live Docs panel (Online Documentation) in the lower right corner.

  • In the environment https://junolab.org [Juno] The keyboard shortcut Ctrl-J, Ctrl-D allows you to display the documentation for the object on which the cursor is located.

Docs.hasdoc(module, name)::Bool specifies whether the name has a docstring. Docs.undocumented_names(module; all) returns undocumented names in the module.

Writing documentation

Julia’s built-in documentation system allows users and package developers to easily document functions, types, and other objects.

The basic syntax is very simple: any string immediately preceding an object (function, macro, type, or instance) is interpreted as documenting that object (such strings are called docstring). Note that there should be no empty lines or comments between the docstring and the documented object. The simplest example:

"Tell whether there are too foo items in the array."
foo(xs::Array) = ...

The documentation is interpreted as https://en.wikipedia.org/wiki/Markdown [Markdown], so you can use padding and borders (`) to separate the sample code from the main text. Strictly speaking, any object can be associated with any other object as its metadata. Markdown is just used by default, but you can create other macro strings and pass them to the @doc macro.

Markdown support is implemented through the standard library `Markdown'. For a complete list of supported syntax, see documentation.

Here is a more complex example still based on Markdown:

"""
    bar(x[, y])

Compute the Bar index between `x` and `y`.

If `y` is unspecified, compute the Bar index between all pairs of columns of `x`.

# Примеры
```julia-repl
julia> bar([1, 2], [1, 2])
1
```
"""
function bar(x, y) ...

The example above demonstrates a number of simple standards that are recommended to be followed when writing documentation.

  1. Always indicate the function signature at the top of the documentation, separating it with four spaces so that it is output as Julia code.

    It can be specified identically to the signature in the Julia code (for example, mean(x::AbstractArray)) or in a simplified form. If possible, optional arguments should be provided with default values (i.e. f(x, y=1)) according to the actual Julia syntax. Optional arguments that do not have a default value should be placed in square brackets (i.e. f(x[, y])`and `f(x[, y[, z]])). Another option is to use multiple lines: one without optional arguments, and the other with their indication. This solution can also be used to document several related methods for a specific function. If the function accepts many named arguments, it is sufficient to include the replacement text <keyword arguments> in the signature (i.e. f(x; <keyword arguments>)), and then provide a complete list of arguments in the #Arguments section (see point 4 below).

  2. After the simplified signature block, describe the function or object’s purpose in one line. If necessary, enter a second paragraph with additional information, separating it with an empty line.

    A one-line description of a function in the documentation should be a single sentence in the form of the third person singular without a subject ("Performs…​", "Returns …​", etc.). A period is placed at the end of the description. If it is difficult to briefly describe the function’s purpose, it may make sense to divide it into several parts (however, this is not mandatory for every case).

  3. Don’t repeat yourself.

    Since the signature already includes the function name, there is no need to start the documentation with the words "Function bar…​", it is better to get straight to the point. Similarly, if the signature already specifies the types of arguments, it would be redundant to mention these types in the description.

  4. Provide a list of arguments only when it is really necessary.

    If the function is simple, it is usually enough to specify the role of the arguments directly in the description of its purpose. The list of arguments will only repeat the information already given elsewhere. However, for complex functions with multiple arguments (especially named arguments), it will be useful to provide a list of them. In this case, insert a bulleted list of arguments (with a - marker) under the heading `# Arguments' after the general description of the function. The list should specify the types of arguments and their default values (if any).

    """
    ...
    # Аргументы
    - `n::Integer`: the number of elements to compute.
    - `dim::Integer=1`: the dimensions along which to perform the computation.
    ...
    """
  5. Provide links to related functions.

    Sometimes there may be functions with similar functionality. To make them easier to find, provide a short list of such functions in the See also paragraph.

    See also [`bar!`](@ref), [`baz`](@ref), [`baaz`](@ref).
  6. Include the code examples in the # Examples section.

    If possible, code examples should be provided in the doctest block. The doctest code block is separated by a border (see Code Blocks), starts with `jldoctest and contains an arbitrary number of commands julia> with input and expected output data simulating Julia’s REPL.

    For doctest blocks, the following is used https://github.com/JuliaDocs/Documenter.jl [Documenter.jl]. For more detailed documentation, see https://juliadocs.github.io/Documenter.jl /[manual] Documenter.

    For example, the following docstring lines show the definition of the variable a and the expected result output in Julia’s REPL.

    """
    Some nice documentation here.
    
    # Примеры
    ```jldoctest
    julia> a = [1 2; 3 4]
    2×2 Array{Int64,2}:
      1  2
      3  4
    ```
    """

    It is not recommended to call rand and other functions related to random number generation in doctest blocks, as their output will vary from Julia session to Julia session. If you need to demonstrate some functionality related to random number generation, then, as one of the options, you can explicitly create your own RNG object (see Random), generate its values and pass it to the functions specified in the doctest.

    The reproducibility of some doctests also depends on the size of the system word in the OS (Int32 or Int64) and from the path separators used (/ or \).

    Spaces matter in doctest! For example, doctest may fail due to incorrect alignment of the structural printout of the array.

    Then you can use make -C doc doctest=true to execute all the doctest blocks in the Julia Manual and API documentation and verify that your example works.

    If you want to show a truncation of the output results, you can enter [...] on the line where the check should stop. This allows you to hide the stack trace (containing non-permanent references to Julia lines of code) when doctest shows an exception being thrown, for example:

    ```jldoctest
    julia> div(1, 0)
    ERROR: DivideError: integer division error
    [...]
    ```

    Examples that are not subject to testing should be written as delimited code blocks starting with julia so that they stand out correctly in the created documentation.

    If possible, the examples should be isolated and working so that the reader can try them out without including any dependent elements in them.

  7. Use backstroke characters to identify the code and expressions.

    To use highlighting, always put Julia IDs and code snippets between the backstroke characters. (`). Equations in LaTeX syntax can be separated by a double backstroke. (`). To do this, use Unicode characters rather than the LaTeX escape sequence, i.e. `α = 1` rather than `\\alpha = 1`.

  8. The initial and final characters """ must be placed on a separate line.

    That is, it is necessary to enter:

    """
    ...
    
    ...
    """
    f(x, y) = ...

    Should not be used:

    """...
    
    ..."""
    f(x, y) = ...

    This will make it clearer where the docstring lines begin and end.

  9. Keep in mind the string length limits in the adjacent code.

    Docstring strings are edited by the same means as the code, so the same standards must be followed for them. It is recommended that the line width should not exceed 92 characters.

  10. In the #Implementation section, provide the information necessary to implement the function in custom types. These data are not intended for users, but for developers, because they explain, for example, which functions should be redefined and which ones automatically use suitable backup options. It is best to separate such information from the main description of the function.

  11. For large docstrings, it is recommended to separate the documentation using the header `# Extended help'. In the normal help mode, only the material above this heading is displayed. To access the full reference data, add another "?" sign at the beginning of the expression (i.e. instead of "?foo" enter "??foo").

Functions and methods

Functions in Julia can have many implementations called methods. Although, as a rule, it is recommended to use universal functions that have strictly one purpose, Julia allows you to document different methods separately, if necessary. Usually, only the most universal methods or even the function itself should be documented (i.e., an object created without any methods using the `function bar end'). Specific methods should be documented only if their behavior differs from the more universal ones. In any case, the documentation should not repeat information that is already available elsewhere. For example:

"""
    *(x, y, z...)

Multiplication operator. `x * y * z *...` calls this function with multiple
arguments, i.e. `*(x, y, z...)`.
"""
function *(x, y, z...)
    # ... [реализация приведена в другом месте] ...
end

"""
    *(x::AbstractString, y::AbstractString, z::AbstractString...)

When applied to strings, concatenates them.
"""
function *(x::AbstractString, y::AbstractString, z::AbstractString...)
    # ... [использует здесь особый код] ...
end

help?> *
search: * .*

  *(x, y, z...)

  Multiplication operator. x * y * z *... calls this function with multiple
  arguments, i.e. *(x,y,z...).

  *(x::AbstractString, y::AbstractString, z::AbstractString...)

  When applied to strings, concatenates them.

When receiving documentation for a universal function, metadata is concatenated for each method using the catdoc function, which, of course, can be redefined for custom types.

Extended use

The macro @doc' binds the contents of its first argument to the second argument and places it in the `META dictionary for specific modules.

To simplify writing documentation, the analyzer processes the macro @doc in a special way: if one argument is given in the call @doc, but another expression follows it after one line break, then this expression is considered the second argument of the macro. Thus, the following syntax will be parsed as a call to @doc with two arguments:

@doc raw"""
...
"""
f(x) = x

This allows you to use not only ordinary string literals as docstrings, but also other expressions (for example, the string of the macro raw'").

When using the macro @doc (as well as the doc function) to obtain documentation, metadata related to this object is searched for in all META dictionaries and the corresponding metadata is returned. The returned object (for example, some Markdown content) is formatted by default. This principle of operation also simplifies interaction with the documentation system through the code. Here’s how you can reuse the same documentation for different versions of a function.:

@doc "..." foo!
@doc (@doc foo!) foo

Usage example with Julia metaprogramming functions:

for (f, op) in ((:add, :+), (:subtract, :-), (:multiply, :*), (:divide, :/))
    @eval begin
        $f(a, b) = $op(a, b)
    end
end
@doc "`add(a, b)` adds `a` and `b` together" add
@doc "`subtract(a, b)` subtracts `b` from `a`" subtract

When writing documentation not in top-level blocks, for example, inside begin, if, for, let and internal constructors, it should be added to the system via @doc. For example:

if condition()
    @doc "..."
    f(x) = x
end

This code adds documentation for f(x) when the condition condition() is met (true). At the same time, even if the function f(x) goes beyond the boundaries of the area after the block, its documentation is preserved.

To simplify the creation of documentation, you can use the capabilities of metaprogramming. When using string interpolation, an additional character $ is required inside docstring, as shown for $($name):

for func in (:day, :dayofmonth)
    name = string(func)
    @eval begin
        @doc """
            $($name)(dt::TimeType) -> Int64

        The day of month of a `Date` or `DateTime` as an `Int64`.
        """ $func(dt::Dates.TimeType)
    end
end

Dynamic documentation

Sometimes, for certain instances of a type, documentation is needed not for the type itself, but separately, depending on the values of the instance fields. In such cases, you can add the method to Docs.getdoc for its custom type, which returns documentation depending on the instance. For example:

struct MyType
    value::Int
end

Docs.getdoc(t::MyType) = "Documentation for MyType with value $(t.value)"

x = MyType(1)
y = MyType(2)

The team'?x will display the Documentation for MyType with value 1, and ?y — Documentation for MyType with value 2.

Syntax Guide

This guide provides a detailed overview of how to add documentation to all Julia syntax constructs for which it is possible.

In the following examples, "..." matches arbitrary docstring strings.

The characters $ and \

The characters $ and \ will continue to be parsed as string interpolation or the beginning of an escape sequence, including in docstring strings. To avoid using escape codes for them, you can use the macro string raw" along with the macro @doc. This is useful when docstring strings contain LaTeX or Julia source code examples with interpolation.:

@doc raw"""
```math
\LaTeX
```
"""
function f end

Functions and methods

"..."
function f end

"..."
f

Adds the docstring string "..." for the function f. The first version of the syntax is preferred, but both are equivalent.

"..."
f(x) = x

"..."
function f(x)
    return x
end

"..."
f(x)

Adds the docstring string "..." for the method f(::Any).

"..."
f(x, y = 1) = x + y

Adds the docstring string "..." for two methods: f(::Any) and f(::Any,::Any).

Macros

"..."
macro m(x) end

Adds the docstring string "..." to define the macro @m(::Any).

"..."
:(@m1)

"..."
macro m2 end

Adds the docstring string "..." for macros named @m1 and `@m2'.

Types

"..."
abstract type T1 end

"..."
mutable struct T2
    ...
end

"..."
struct T3
    ...
end

Adds the docstring string "..." for the types T1, T2 and T3.

"..."
T1

"..."
T2

"..."
T3

Adds the docstring string "..." for the types T1, T2 and T3. The previous version of the syntax is preferred, but both are equivalent.

"..."
struct T
    "x"
    x
    "y"
    y

    @doc "Inner constructor"
    function T()
        new(...)
    end
end

Adds the docstring string "..." for the type T, "x" for the field T.x, "y" for the T' field.y and "Inner constructor" for the inner constructor T(). Also applicable to mutable struct types.

Modules

"..."
module M end

module M

"..."
M

end

Adds the docstring string "..." for the module M. The syntax with the addition of docstring over Module is preferred, but both options are equivalent.

"..."
baremodule M
# ...
end

baremodule M

import Base: @doc

"..."
f(x) = x

end

When documenting the baremodule by placing a docstring above the expression, the macro @doc is automatically imported into the module. If the module expression is not documented, such an import must be performed manually.

Global variables

"..."
const a = 1

"..."
b = 2

"..."
global c = 3

Adds the string docstring "..." for the bindings (Binding) of a, b and c.

Bindings (Binding) allow you to save a link to a specific symbol (Symbol) in a module (Module) without saving the direct value of the link.

When the definition of const only specifies an alias for another definition, for example, as in the case of the function div and its alias ÷ in Base, it is not the alias that needs to be documented, but the function itself.

If an alias is documented, and not the actual definition, then when searching for the actual definition, the documentation system (mode ?) will not return docstring strings associated with an alias.

For example, you should write:

"..."
f(x) = x + 1
const alias = f

Should not be used:

f(x) = x + 1
"..."
const alias = f
"..."
sym

Adds the docstring string "..." for the value associated with sym'. However, it is recommended to document the `sym object where its definition is located.

Multiple objects

"..."
a, b

Adds the docstring string "..." for the elements a and b. Both should be expressions for which documentation is possible. This syntax is equivalent to the following.

"..."
a

"..."
b

Any number of expressions can be documented in this way. This syntax is useful when there are two related functions, such as the immutable and mutable versions of f and `f!'.

The code generated by macros

"..."
@m expression

Adds the docstring string "..." for the expression formed when opening the @m expression. This allows you to document expressions preceded by @inline, @noinline, @generated or any other macros, just like expressions without macros.

When writing macros, keep in mind that only macros that form a single expression automatically support docstring. If a macro returns a block containing several nested expressions, then to document the nested expression, you need to mark it with a macro. @__doc__.

The macro '@enum` uses @__doc__' to document `Enum. Consider its definition as an example of using `@__doc__' properly.

@__doc__(ex)

Low-level macro used to mark expressions returned by a macro that should be documented. If more than one expression is marked then the same docstring is applied to each expression.

macro example(f)
    quote
        $(f)() = 0
        @__doc__ $(f)(x) = 1
        $(f)(x, y) = 2
    end |> esc
end

@__doc__ has no effect when a macro that uses it is not documented.