Julia: Documenting return types using Julia syntax

Created on 14 Jul 2017  Â·  14Comments  Â·  Source: JuliaLang/julia

It looks like Base is using the following convention to document return types

"""
    foo(x::Integer) -> Integer
"""
foo(x::Integer) = x

The proposal is to use Julia's return syntax instead, e.g.

"""
    foo(x::Integer)::Integer
"""
foo(x::Integer) = x

related https://github.com/JuliaLang/julia/issues/4902

doc docsystem

Most helpful comment

That looks backwards, from the usual syntax where you would type F = lufact(...). Perhaps

"""
    F = lufact(A::SparseMatrixCSC)::UmfpackLU

Compute the LU factorization of a sparse matrix A.
[...]
"""

but that takes focus from the function itself so that's not very nice.

All 14 comments

Another example to consider

"""
    @__LINE__ -> Int
"""

"""
    @__LINE__::Int
"""

Currently the arrow is used inconsistently: sometimes to express the return type, sometimes to express the return value (e.g. randn!). I find it nice to formally specify the return value, when appropriate, so your proposal would allow to reserve the arrow for this.

I guess that would be fine, or we could use = to specify the return value?

There are also docstrings of the following form where the return value is given a variable name F which is used later referenced

"""
    lufact(A::SparseMatrixCSC) -> F::UmfpackLU

Compute the LU factorization of a sparse matrix A.
[...]
"""

from lufact(::SparseMatrix). At least the :: notation is used here also.

Edit: What I'm trying to say is that the syntax proposed in the OP would not work in this case, when giving a name and just not a type to the return value.

@fredrikekre How about the follwoing ( with @JeffBezanson's idea for return values)

"""
    lufact(A::SparseMatrixCSC)::UmfpackLU = F

Compute the LU factorization of a sparse matrix A.
[...]
"""

That looks backwards, from the usual syntax where you would type F = lufact(...). Perhaps

"""
    F = lufact(A::SparseMatrixCSC)::UmfpackLU

Compute the LU factorization of a sparse matrix A.
[...]
"""

but that takes focus from the function itself so that's not very nice.

Listing additional ideas:

# for types use :: and return values use =

# opt 1
"""
    lufact(A::SparseMatrixCSC) = (F::UmfpackLU)

Compute the LU factorization of a sparse matrix A.
[...]
"""

# opt 2
"""
    lufact(A::SparseMatrixCSC)::UmfpackLU = F

Compute the LU factorization of a sparse matrix A.
[...]
"""

# for types use :: and return values use ->

# opt 3
"""
    lufact(A::SparseMatrixCSC) -> F::UmfpackLU

Compute the LU factorization of a sparse matrix A.
[...]
"""

# opt 4
"""
    lufact(A::SparseMatrixCSC)::UmfpackLU -> F

Compute the LU factorization of a sparse matrix A.
[...]
"""


I like = and :: for values and types, respectively.

Listing additional ideas:

For option 1 and 3, it's not clear what it would lool like when there are no return value. Also I think a return value is only useful to specify when it's also an argument name (i.e. to document the identity of objects), or at least when it is used in the docstring (but this could otherwise be introduced in the docstring itself when useful, so that the signature is minimal).
For me option 2 is confusing, as this looks like a function definition: i.e. it's valid code provided F is already defined. So I prefer option 4.

I favour options 3 and 4. But I suspect in many cases the name/description of the returned object could be removed and replaced with a mention in the docstring text. Also note that with NamedTuple, we should soon have an actual syntax for functions which return several values as a tuple (which would return a NamedTuple), so it would make sense to use it in the docstring signature.

I prefer using actual julia syntax, as suggested above by @fredrikekre. Indeed I've actually snuck it in once already. I don't think it distracts too much.

From discussion on slack:

Lyndon White [12:33 PM] @oxinabox

The convention of putting
foo(x::T) ->S in the docstring of a function to indicate that it returns a object of type S seems like it should be being written as
foo(x::T)::S
to be inline with how the code is actually written if annotating the return type

Stefan Karpinski [12:39 PM] @StefanKarpinski

that’s fine when ::S is valid Julia syntax
a lot of the doc string annotations are not actual valid code though
they either indicate a value that’s returned or are pseudo-syntax
in which case using -> seems better to indicate that it’s not valid input syntax

Lyndon White [12:40 PM]

using ->s makes sense to me when it is pseudo-syntac to indicate a value that would be returned.
using ::S to me make sense when it is pseudo-syntac to indicate the type of the value that would be returned. (edited)

Stefan Karpinski [12:54 PM]

that seems like a sensible way to do it

Jiahao [12:58 PM] @jiahao

The -> way is the Python way :grinning:

Matt Bauman [1:37 PM] @mbauman

I suppose we could use --> or → to make it slightly more clear that it’s pseudo-syntax (edited)

Lyndon White [1:39 PM]

It is in a docstring, it is pseudosyntax
Docstrings also often use foo(x, [y]) to indicate that y is an optional argument.

Matt Bauman [1:57 PM]

Oh, your gripe isn’t so much about -> being function syntax as it is that we _do_ have a syntax for return types?

Michael K. Borregaard [2:03 PM] @mkborregaard

I have to say it’s always really confused me to see the anonymous function syntax used in a completely different way

Stefan Karpinski [2:11 PM] @StefanKarpinski

historically, it was because the manual was in Restructured Text for a while

David Sanders [3:03 PM] @dpsanders

Does an average user who is looking at the docstring understand what -> S or ::S is supposed to mean though? Maybe it should be written out more explicitly ("returns object of type S")

Kristoffer Carlsson [3:04 PM] @KristofferC

You learn it and then you know :stuck_out_tongue:

Chris de Graaf [3:14 PM] @christopher-dG

imo -> is super clear, I never even considered anonymous function syntax when looking at it until reading this discussion

Simon Byrne [3:31 PM] @simonbyrne

I would prefer actual Julia syntax, e.g. s = foo(...) or s::S = foo(....)

Fredrik Ekre [3:35 PM] @fredrikekre

Take your gripes here: https://github.com/JuliaLang/julia/issues/22804

David Sanders [3:57 PM]

It's definitely useful to indicate to the user how the function should actually be called
So I would vote for s = foo(...)

Stefan Karpinski [4:01 PM]

that might be confusing for Matlab users who could think that you can actually defined functions that way which you cannot, of course

Should we do anything about this ? Has the ship sailed (an autoformatter could probably take care of this)

I was originally in favor of this and still think it's ok when the return type can be clearly and correctly written in Julia syntax, but I tend to prefer using the -> pseudo-syntax using a type "expression" that will make sense to the reader rather than necessarily being valid Julia syntax. For example, in the docs for the Tar.jl pacakge, I use create([ predicate, ] dir, [ tarball ]; [ skeleton ]) -> tarball to indicate that the tarball path / IO handle / whatever is returned from the function. This can't be expressed with Julia syntax but seems like more useful information to the reader than what Julia asserts the return type to be.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ararslan picture ararslan  Â·  3Comments

omus picture omus  Â·  3Comments

m-j-w picture m-j-w  Â·  3Comments

Keno picture Keno  Â·  3Comments

tkoolen picture tkoolen  Â·  3Comments