Using Documenter.jl, I keep getting these warnings:
┌ Warning: 60 docstrings not included in the manual:
│
│ ProtoSyn.Calculators.TorchANI.r_xml_travel! :: Union{Tuple{T}, Tuple{Union{LightXML.XMLDocument, LightXML.XMLElement}, String, Vector{T}}} where T<:AbstractFloat
│ ProtoSyn.Clustering.dunn_index :: Union{Tuple{T}, Tuple{Vector{T}, Matrix{T}}} where T<:AbstractFloat
│ ProtoSyn.Calculators.get_available_energy_function_components :: Tuple{Module}
│ Base.resize! :: Tuple{ProtoSyn.Calculators.VerletList, Int64}
│ ProtoSyn.Common
(...)
I want to ignore some (most) of these docstrings (they exist in the code base but I do not want to export them to the final documentation website). How can I ignore individual docstrings?
You should try suppressing such warnings by specifying the checkdocs keyword option when calling makedocs(). Using checkdocs=:exports complains only if the unused docstring's function is exported. If you use checkdocs=:none in makedocs that should cause makedocs to ignore the unused docstrings. You might lose some error warnings for malformed docstrings though.
Related
I have a module, say, called Constants,
module Constants
const zero = 0.0 :: Float64
const czero = 0.0 + 0.0im :: Complex
end
I know like I can define like zero as Float64. But How do I define a "Complex" and "Float64" variable such as czero? Currently I use Complex, but I want to be more specific. If I use ComplexF64
const czero = 0.0 + 0.0im :: ComplexF64
it gives me an error,
ERROR: LoadError: TypeError: in typeassert, expected Complex{Float64}, got a value of type Complex{Bool}
So what concrete type of Complex should I use?
I give each variable a concrete type is because I heard that if the code looks like Fortran it can run like Fortran, because I define the type first so Julia do not have to convert the type which can be very slow.
This question is not quite clear, but perhpas what you need is zero:
julia> zero(ComplexF64)
0.0 + 0.0im
julia> dump(zero(ComplexF64))
ComplexF64
re: Float64 0.0
im: Float64 0.0
Other options include using the constructor such as ComplexF64(0.0) or ComplexF64(0.0,0.0) or using the complex(0.0) function. These are all type stable.
::
With the ::-operator type annotations are attached to expressions and variables in programs. See the manual section on Type Declarations.
Outside of declarations :: is used to assert that expressions and variables in programs have a given type.
Examples
≡≡≡≡≡≡≡≡≡≡
julia> (1+2)::AbstractFloat
ERROR: TypeError: typeassert: expected AbstractFloat, got a value of type Int64
julia> (1+2)::Int
3
With this in mind, obviously julia considers the declaration invalid because of operator precedence, so just put parentheses if you want to do the declaration this way
const czero = (0.0 + 0.0im) ::ComplexF64
I also second the opinion above: if you're just trying to declare zeros then what you need is zero
I have a struct defined as follows:
julia> struct test
test1::Int64
test2::Float64
end
I want to be able to see the names of the attributes in the struct as well as the type. What is the most straight forward way to do this? I know I can do:
julia> t = test(1,1.0)
test(1, 1.0)
julia> fieldnames(typeof(t))
(:test1, :test2)
but I would like to see the attribute name and type together.
Use fieldtypes(typeof(t))
julia> DataFrame(name=[fieldnames(typeof(t))...], type=[fieldtypes(typeof(t))...])
2×2 DataFrame
│ Row │ name │ type │
│ │ Symbol │ DataType │
├─────┼────────┼──────────┤
│ 1 │ test1 │ Int64 │
│ 2 │ test2 │ Float64 │
Regarding the other answer note that dump outputs always the entire data structure which is not good for fields having complex types. Try doing dump on a struct that has a Dict field to find out my point (or just try in the console) dump(Dict()).
The most straight forward way to do this would be to use the dump method:
help?> dump
search: dump
dump(x; maxdepth=8)
Show every part of the representation of a value. The depth of the
output is truncated at maxdepth.
So in this case, it would show:
julia> dump(t)
test
test1: Int64 1
test2: Float64 1.0
See here for more details: https://docs.julialang.org/en/v1/base/io-network/#Base.dump
(Question refers to Julia version v1.5)
I'm trying to understand how the #deprecate macro works in Julia. The documentation is unfortunately not clear to me:
#deprecate old new [ex=true]
Deprecate method old and specify the replacement call new. Prevent
#deprecate from exporting old by setting ex to false. #deprecate
defines a new method with the same signature as old.
Warning:
As of Julia 1.5, functions defined by #deprecate do not print warning when julia is run without the --depwarn=yes flag set, as the default value of --depwarn option is no. The warnings are printed from tests run by Pkg.test().
Examples
julia> #deprecate old(x) new(x)
old (generic function with 1 method)
julia> #deprecate old(x) new(x)
false old (generic function with 1 method)
So what do I do?
function old(x::Int)
print("Old behavior")
end
function new(x::Int)
print("New behavior")
end
# Adding true/false argument doesn't change my observations.
#deprecate old(x) new(x) # false
old(3)
# Prints "Old behaviour". No warning.
# Also: The deprecation is not mentioned in the help (julia>? old)
The aim of this #deprecate macro seems to be replacing functions? I find that counterintuitive. How can mark a function as deprecated (i.e. users should receive a warning and a hint what to use as a replacement, also it should be in the documentation)?
edit: I noticed my error. The signatures (in my case the ::Int) have to be identical for this to work. However, how do I get a warning?
Imagine you have this method as part of the public API of your library in version 1:
# v1.0.0
mult3(x::Int) = 3x
In version 2, you'd like to stop supporting mult3 (which is a breaking change). But the same feature will still be available using a more general method:
# v2.0.0
mult(x, y) = x * y
Users of version 1 are used to using mult3, which means that their code will break when they will update to v2. Therefore, you might want to release an intermediate version in the v1.x family, where mult3 exists but is deprecated and implemented in terms of mult:
# v1.1 - transition
# This is the new API for v2
mult(x, y) = x*y
# The old API is still supported, but deprecated and implemented using the old one
#deprecate mult3(x::Int) mult(3, x)
# The above is more or less equivalent to defining
# function mult3(x::Int)
# # print an error message is `--depwarn` has been set
# return mult(3, x)
# end
The v1 API is not broken in late v1.x versions, but users calling deprecated methods will see the following kind of messages to help them transition to the newer v2 API:
julia> mult3(14)
┌ Warning: `mult3(x::Int)` is deprecated, use `mult(3, x)` instead.
│ caller = top-level scope at REPL[3]:1
└ # Core REPL[3]:1
42
(but starting with Julia 1.5, the warning will only be shown if --depwarn=yes has been provided in Julia's command line or if it appears in a test suite run by Pkg.test())
Alternatively, and as mentioned in comments, you may want to leave the old implementation around, simply warning users when they call it. To this end, you can use Base.depwarn directly:
# v1.1 - transition
# This is the new API for v2
mult(x, y) = x*y
# The old API is still supported, but deprecated
# It is implemented by itself:
function mult3(x)
Base.depwarn("`mult3(x)` is deprecated, use `mult(3,x)` instead.", :mult3)
return 3x
end
When --depwarn=yes has been provided in Julia's command line, this produces the same kind of warning as #deprecate:
julia> mult3(14)
┌ Warning: `mult3(x)` is deprecated, use `mult(3,x)` instead.
│ caller = top-level scope at REPL[4]:1
└ # Core REPL[4]:1
42
Starting with Julia 1.6, depwarn will accept a keyword argument to force warning emission even when users haven't asked for them with --depwarn=yes:
julia> Base.depwarn("Foo is deprecated", :foo, force=true)
┌ Warning: Foo is deprecated
│ caller = ip:0x0
└ # Core :-1
As an old C programmer, I use lots of asserts in my code. Now I want to globally switch them off to speed things up. What is the best practice way to do that?
There is no built-in option / command line flag to disable #asserts globally, yet(!).
For now, you can define a #myassert macro which, depending on a global switch, is a no-op or a regular #assert:
asserting() = false # when set to true, this will enable all `#myassert`s
macro mayassert(test)
esc(:(if $(#__MODULE__).asserting()
#assert($test)
end))
end
f(x) = #mayassert x < 2
(taken from https://discourse.julialang.org/t/assert-alternatives/24775/14)
You could put your #assert statements in a #debug block. Then the #assert call is desactivated, unless you activate debugging either globally (ENV["JULIA_DEBUG"] = "all") or just for your module (ENV["JULIA_DEBUG"] = "NameOfYourModule")
julia> #debug begin
#assert 1==2
end
#or
#debug #assert 1==2 # assert is not called
julia> ENV["JULIA_DEBUG"] = "all" # enable debugging
"all"
julia> #debug begin
#assert 1==2
end
┌ Error: Exception while generating log record in module Main at REPL[4]:1
│ exception =
│ AssertionError: 1 == 2
│ Stacktrace:
│ [1] top-level scope at REPL[4]:2
│ [2] top-level scope at logging.jl:319
| ...
└ # Main REPL[4]:1
Although it would be nice to have this feature, the need for #asserts in your code can be reduced by defining and dispatching on your own types. For example, suppose you have a function foo(t::TimeType) = t, but you only want to accept times that are a multiple of five minutes. You can create a new type with this requirement:
using Dates
struct FiveMinuteMultiple
t::DateTime
function FiveMinuteMultiple(y, m, d, h, mi)
if mi%5 != 0
throw(DomainError(m, "the minute argument must be a multiple of 5"))
end
new(DateTime(y, m, d, h, mi))
end
end
Now you literally can't create a FiveMinuteMultiple that is not a multiple of five minutes:
julia> t = FiveMinuteMultiple(2016, 7, 15, 4, 23)
ERROR: DomainError with 7:
the minute argument must be a multiple of 5
Stacktrace:
[1] FiveMinuteMultiple(::Int64, ::Int64, ::Int64, ::Int64, ::Int64) at ./REPL[2]:5
[2] top-level scope at none:0
julia> t = FiveMinuteMultiple(2016, 7, 15, 4, 25)
FiveMinuteMultiple(2016-07-15T04:25:00)
So if you now define foo(t::FiveMinuteMultiple) = t, you no longer need an #assert to verify that the argument is a time that is a multiple of five minutes. Sure, you still have to pay the cost of argument checking when you construct the FiveMinuteMultiple, but unless it's a hot inner loop you probably want that additional data validation anyways.
Advantages:
Method dispatch guarantees that the arguments to your functions are of the correct type.
You can avoid duplicating the same assertion across multiple functions foo(t::FiveMinuteMultiple), bar(t::FiveMinuteMultiple), and baz(t::FiveMinuteMultiple).
The more specific argument annotation alerts users and developers that the function expects a more specific type of data.
Disadvantages:
Depending on your use case, you may need to forward various methods to the data field within your struct. For example, for FiveMinuteMultiple you may need to forward methods such as day, hour, etc, to the t field of the struct.
Adding a new concept (type) to represent assertions about your data might introduce an unnecessary layer of abstraction.
When trying to clean up the code using #code_warntype I get the type instability of ::AbstractArray{T,1} when it is not expected.
A data frame is the argument of the function FUNC1, and a particular COLUMN in it is used within the function. I've defined the type for this COLUMN within the function as Array{Float64,1}. But, when I run #code_warntype on the function, ::AbstractArray{T,1} appears in the output.
function FUNC1(df::DataFrame)
df_COL=df[:COLUMN]::Array{Float64,1}
.......
end
Expected result is that there should be no type instability because the type has been specified for that column.
Actual results:
Body::Tuple{Float64,Float64}
│ 159 1 ── %1 = invoke Base.getindex(_2::DataFrame, :COLUMN::Symbol)::AbstractArray{T,1} where T
│ │ (Core.typeassert)(%1, Array{Float64,1})
│ │ %3 = π (%1, Array{Float64,1})
That's printing out exactly as I'd expect. There are three things that are happening here:
First the indexing: %1 = invoke Base.getindex — this is doing the indexing. It can return a vector of any type. This is indeed type-unstable.
Then the typeassert: (Core.typeassert)(%1, Array{Float64,1}) — this ensures that what getindex returned (in %1) is a Vector{Float64}. If it's not, Julia will throw an error.
And now the payoff: %3 = π (%1, Array{Float64,1}) — now that vector can be considered a Vector{Float64} since every other type would result in an error. From here on out, computations with the vector should be type-stable.
Adding type assertions like that don't "fix" the instability at its root, they simply patch it up so everything afterwards is fast.