Skip to content
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

Documenting return types using Julia syntax #22804

Open
musm opened this issue Jul 14, 2017 · 16 comments
Open

Documenting return types using Julia syntax #22804

musm opened this issue Jul 14, 2017 · 16 comments
Labels
docs This change adds or pertains to documentation docsystem The documentation building system

Comments

@musm
Copy link
Contributor

musm commented Jul 14, 2017

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 #4902

@ararslan ararslan added the docs This change adds or pertains to documentation label Jul 14, 2017
@musm
Copy link
Contributor Author

musm commented Jul 14, 2017

Another example to consider

"""
    @__LINE__ -> Int
"""
"""
    @__LINE__::Int
"""

@rfourquet
Copy link
Member

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.

@JeffBezanson
Copy link
Member

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

@fredrikekre
Copy link
Member

fredrikekre commented Jul 14, 2017

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.

@musm
Copy link
Contributor Author

musm commented Jul 15, 2017

@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.
[...]
"""

@fredrikekre
Copy link
Member

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.

@musm
Copy link
Contributor Author

musm commented Jul 15, 2017

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.
[...]
"""

@TotalVerb
Copy link
Contributor

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

@rfourquet
Copy link
Member

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.

@kshyatt kshyatt added the docsystem The documentation building system label Jul 18, 2017
@nalimilan
Copy link
Member

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.

@simonbyrne
Copy link
Contributor

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.

@oxinabox
Copy link
Contributor

oxinabox commented Dec 3, 2018

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 😀

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 😛

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: #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

@musm
Copy link
Contributor Author

musm commented Jul 23, 2020

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

@StefanKarpinski
Copy link
Member

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.

@jishnub
Copy link
Contributor

jishnub commented Sep 9, 2023

Why not have an explicit Returns section like numpy instead of making this cryptic and expecting users to catch up? Looks like this has confused new users in the past.

@timholy
Copy link
Member

timholy commented Sep 12, 2023

I agree that using -> is confusing. The thing I dislike about foo(x::Integer)::Integer is that it gets confusing if the return type is Tuple{A,B,C,D,...}. I think that perhaps

    a::Int, b::String = foo(...)

might be clearer? I know some folks frown on naming the outputs, but it frankly makes it easier to talk about them meaningfully in the docs. E.g., "lookup = foo(...) where lookup[m::Method] returns the location..." seems clearer than lookup::Dict{Method,LineNumberNode}.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs This change adds or pertains to documentation docsystem The documentation building system
Projects
None yet
Development

No branches or pull requests