In the source of the package SimpleArgParse.jl, the definition of mutable struct ArgumentParser
contains field definitions intersperses by strings like the following:
struct Foo
"x value"
x::Int
"x name"
xname::String
end
The code above accepted by Julia. Why is it a valid code? Do the strings have any function?
Strings interspersed with functions and struct definitions (and values and some other things) are used to attach docstrings that are displayed when using the help prompt (accessed by beginning a line in the REPL with ?). But I’ll admit I had no idea it was possible to docstring a struct’s field.
julia> "docstring for Foo"
struct Foo
"docstring for Foo.x"
x::Int
"docstring for Foo.name"
name::String
end
Foo
help?> Foo
search: Foo floor fourthroot pointer_from_objref OverflowError RoundFromZero unsafe_copyto! functionloc
docstring for Foo
help?> Foo.x
docstring for Foo.x
help?> Foo.name
docstring for Foo.name
julia> begin
"why this"
struct X
"why that"
y::Int
end
end
X
help?> X.y
why that
help?> X
search: X xor exp Expr exp2 exit axes expm1 exp10 export extrema extrema! exponent Exception expanduser
why this
julia> Meta.@lower begin
"why this"
struct X
"why that"
y::Int
end
end
...omitted the lowered struct code...
10 ┄ %37 = (Base.Docs.Binding)(Main, :X)
│ %38 = (Core.svec)("why this")
│ %39 = (Pair{Symbol, Any})(:y, "why that")
│ %40 = (Dict{Symbol, Any})(%39)
│ %41 = (Pair)(:fields, %40)
│ %42 = (Dict{Symbol, Any})(:path => "REPL[24]", :linenumber => 2, :module => Main, %41)
│ %43 = (Base.Docs.docstr)(%38, %42)
│ %44 = Core.apply_type(Union)
│ %45 = (Base.Docs.doc!)(Main, %37, %43, %44)
└─── return %45
))))
As implied, the lowered Base.Docs code vanishes if you don’t start with a string over the struct, even if there are strings over the fields:
julia> begin
struct Y
"why that"
z::Int
end
end
help?> Y.z
Y has fields z.
help?> Y
search: Y yield yieldto Sys Type hypot typeof Symbol TypeVar typemin typemax symlink symdiff typejoin symdiff! TypeError
No documentation found.
...
Reasonably, ArgumentParser has an overall docstring:
"Command-line argument parser with key-value stores and attributes."
mutable struct ArgumentParser
Yes, my first guess was of course those are docstrings, but
help?> Foo.x
Foo has fields x, and xname.
was not what I expected.
Now I see:
struct Foo
"x value"
x::Int
"x name"
xname::String
end
"this is Baz"
struct Baz
"x value"
x::Int
"x name"
xname::String
end
;
help?> Foo.x
Foo has fields x, and xname.
help?> Baz.x
x value
The Types section of Documentation · The Julia Language covers it, but it does not explain that you need a docstring for the overall struct to make field docstrings work, it just shows an example. Like mikmoore said, I also think this is a relatively obscure feature. If the fields are public, it’s beneficial to document them in the type’s docstring, and if the fields are internal, the public higher-level methods are documented instead.
I am curious how the upcoming public keyword will factor into this. REPL-accessible docstrings can be justified for internal details, and separating the docstrings of the fields and the overall struct do help with differentiating internal fields and the public struct type, but there’s an ambiguity there for public fields.