I’m reading the source of Javis.jl right now, and I see that function docstrings have type annotations for arguments, but the arguments themselves are not explicitly typed. If the type of the argument is going to be given in the docstring anyways, why not just do f(x::Number) = x^2 (with appropriate docstring) instead of something like
"""
f(x)
Get the square of a number 'x'
# Arguments
- 'x::Number': The number to be squared
# Returns
- 'Number': The square of the input
"""
f(x) = x^2
It seems like if it’s possible to annotate the type in the function definition such that it would be annotated in the docstring, for the sake of readability and optimization, it should be. It’s possible this has something to do with the package being “under heavy development”, but under what circumstances is it appropriate to assert types in the function definition when they’re annotated in the docstring?
TYPEDSIGNATURES from DocStringExtensions makes it pretty easy to auto-generate these kinds of annotated docstrings in exactly the way you’re asking for:
julia> """
$(TYPEDSIGNATURES)
Do something cool!
"""
foo(x::Number) = x + 1
foo
help?> foo
search: foo floor pointer_from_objref OverflowError RoundFromZero unsafe_copyto! functionloc StackOverflowError @functionloc OutOfMemoryError UndefKeywordError unsafe_pointer_to_objref
foo(x::Number) -> Any
Do something cool!
Note how the x::Number has been automatically extracted from the method definition and inserted into the docstring.
Just to give a counter-point, it’s often useful to just not restrict method signatures unless you actually have a reason to. The docstring is telling you it expects to get numbers, but maybe you can stick a square matrix in there and it’ll be okay, or even a string:
That makes sense and it is one of the strengths of Julia. I made a habit of annotating methods unless they were deliberately type agnostic in my own code and was thrown by the documentation-only annotation because it seems less efficient to compile, but I see the value in assuming methods will be used responsibly for the sake of fast, flexible development.
Just a side note, there is no difference in the efficiency at compile time or runtime for these functions if you put type constraints or not. Type annotations in Julia methods are purely for dispatch.
This is different from almost every other optionally typed, JIT compiled dynamic language, so it’s a constant source of confusion.
Yeah, but then errors are caught later, if at all. I use f(x) = x^2 in generic open source library code, and f(x::Number) = x^2 in my end-user private code when I don’t expect to use a matrix. I can always change it later, and it’s better documentation.
Along those lines, I also started using Any type aliases for documentation. Eg.
const Functor = Any
run_with_context(f::Functor, ctx, ...) = ...
It makes the code clearer, until Julia starts supporting interfaces/contracts/etc.