https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L203
Do import Libdl instead
https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L204
Prefer import SparseArrays so that all subsequent usages require SparseArrays. as the prefix. It makes things easier to maintain in the future, and it avoids SparseArrays releasing a new public symbol that conflicts with one of yours
https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L213
Remove the = nothing. This creates a new method Base.showerror(io::IO) = print(io, nothing.message) which is both type piracy (creating a method with types that you do not own) and it is also broken.
https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L218-L228
Reconsider all of these. You shouldn't need a global Functions dictionary.
https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L242-L268
Reconsider this. See how Xpress.jl searches for the library at Pkg.build time https://github.com/jump-dev/Xpress.jl/blob/master/deps/build.jl or loads it on __init__: https://github.com/jump-dev/Xpress.jl/blob/3f08ab203011da3375c1dd1af72cbb16c40b00bf/src/Xpress.jl#L22
https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L280-L284
This can be
p_major, p_minor, p_build = Ref{Cint}(0), Ref{Cint}(0), Ref{Cint}(0)
ccall((:XPRSgetversionnumbers, libxprs), Cint, (Ref{Cint}, Ref{Cint}, Ref{Cint}), p_major, p_minor, p_build)
# or
p_major, p_minor, p_build = Ref{Cint}(0), Ref{Cint}(0), Ref{Cint}(0)
@ccall libxprs.XPRSgetversionnumbers(p_major::Ref{Cint}, p_minor::Ref{Cint}, p_build::Ref{Cint})::Cint
https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L376
You don't need these explicit export because you have the export loop in XpressAPI.jl.
https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L705-L715
See the equivalent code in Xpress.jl: https://github.com/jump-dev/Xpress.jl/blob/3f08ab203011da3375c1dd1af72cbb16c40b00bf/src/Xpress.jl#L234-L239. Note that you need GC.@preserve to retain the buffer. Also, your retcode is unchecked (although I just noticed that ours is too), and the try-catch is unnecessary because I don't think it's possible for that to go wrong. Something similar appears in many other places.
https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L772
Statements at the top level of a module don't need global in front of them. They are by default.
https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L11954
It's very tempting to play laissez-faire with types in Julia. But we typically find that it's better to start restrictive and widen only if there is demand. Instead of AbstractString in places, consider using String.
The same happens here:
https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L11999-L12001
You could make XPRSsetcheckedmode(checkedmode::Int32)::Nothing and force the complexity onto the caller. Rather than casting from an checkedmode::Any input into a Int32(checkedmode). (That might fail.)
https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L12013
The docstring is incorrect. We typically expect )::checkedmodeto be the type, not the name of the return value. SoXPRSgetcheckedmode()::Int32`.
https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L12033
Here and throughout, consider explicit return statements. They make the code easier to read.
https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L12080
This is unsafe behaviour. You need
GC.@preserve version_buffer
version = unsafe_string(pointer(version_buffer))
end
https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L12348
Here's a question that needs a much longer discussion amongst yourselves. How do you translate Julia types to C types and vice versa? So in this one, filename can be nothing, which gets converted to C_NULL internally. The alternative would be to require the user to pass C_NULL directly. The docstring is also missing an explanation of what nothing does.
https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L12447-L12466
Same question about types here. Prefer concrete types because:
https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L12487-L12493
it might be that rhs::AbstractVector{Number} but no method is defined for Base.convert(::Type{Vector{Float64}}, rhs). Similarly, if you leave c_rhs as a AbstractVector{Float64} there might not be a method to convert it to a Ptr{Float64}. As one example:
julia> x = 1.0:4.0
1.0:1.0:4.0
julia> x isa AbstractVector{Float64}
true
julia> y = Base.cconvert(Ptr{Cdouble}, x)
1.0:1.0:4.0
julia> z = Base.unsafe_convert(Ptr{Cdouble}, y)
ERROR: conversion to pointer not defined for StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}
Stacktrace:
[1] error(s::String)
@ Base ./error.jl:44
[2] unsafe_convert(::Type{Ptr{…}}, a::StepRangeLen{Float64, Base.TwicePrecision{…}, Base.TwicePrecision{…}, Int64})
@ Base ./pointer.jl:66
[3] top-level scope
@ REPL[13]:1
Some type information was truncated. Use `show(err)` to see complete types.
The "flexibility" of types in Julia is both a blessing and a curse. It makes it easy to write high level code, but it can make low-level library code hard to write in a generic fashion.
https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L29841-L29853
This appears to be the only function that is 1-based indexing instead of 0-based?
https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L203
Do
import Libdlinsteadhttps://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L204
Prefer
import SparseArraysso that all subsequent usages requireSparseArrays.as the prefix. It makes things easier to maintain in the future, and it avoids SparseArrays releasing a new public symbol that conflicts with one of yourshttps://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L213
Remove the
= nothing. This creates a new methodBase.showerror(io::IO) = print(io, nothing.message)which is both type piracy (creating a method with types that you do not own) and it is also broken.https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L218-L228
Reconsider all of these. You shouldn't need a global
Functionsdictionary.Reconsider this. See how Xpress.jl searches for the library at
Pkg.buildtime https://github.com/jump-dev/Xpress.jl/blob/master/deps/build.jl or loads it on__init__: https://github.com/jump-dev/Xpress.jl/blob/3f08ab203011da3375c1dd1af72cbb16c40b00bf/src/Xpress.jl#L22https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L280-L284
This can be
https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L376
You don't need these explicit
exportbecause you have the export loop inXpressAPI.jl.https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L705-L715
See the equivalent code in Xpress.jl: https://github.com/jump-dev/Xpress.jl/blob/3f08ab203011da3375c1dd1af72cbb16c40b00bf/src/Xpress.jl#L234-L239. Note that you need
GC.@preserveto retain the buffer. Also, yourretcodeis unchecked (although I just noticed that ours is too), and thetry-catchis unnecessary because I don't think it's possible for that to go wrong. Something similar appears in many other places.https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L772
Statements at the top level of a module don't need
globalin front of them. They are by default.https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L11954
It's very tempting to play laissez-faire with types in Julia. But we typically find that it's better to start restrictive and widen only if there is demand. Instead of
AbstractStringin places, consider usingString.The same happens here:
https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L11999-L12001
You could make
XPRSsetcheckedmode(checkedmode::Int32)::Nothingand force the complexity onto the caller. Rather than casting from ancheckedmode::Anyinput into aInt32(checkedmode). (That might fail.)https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L12013
The docstring is incorrect. We typically expect )::checkedmode
to be the type, not the name of the return value. SoXPRSgetcheckedmode()::Int32`.https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L12033
Here and throughout, consider explicit
returnstatements. They make the code easier to read.https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L12080
This is unsafe behaviour. You need
https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L12348
Here's a question that needs a much longer discussion amongst yourselves. How do you translate Julia types to C types and vice versa? So in this one,
filenamecan benothing, which gets converted toC_NULLinternally. The alternative would be to require the user to passC_NULLdirectly. The docstring is also missing an explanation of whatnothingdoes.https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L12447-L12466
Same question about types here. Prefer concrete types because:
https://github.com/fico-xpress/XpressAPI.jl/blob/f20e039fea38b2cd964d99d3c2c3e681ff874fe2/src/C_wrapper/C_wrapper.jl#L12487-L12493
it might be that
rhs::AbstractVector{Number}but no method is defined forBase.convert(::Type{Vector{Float64}}, rhs). Similarly, if you leavec_rhsas aAbstractVector{Float64}there might not be a method to convert it to aPtr{Float64}. As one example:The "flexibility" of types in Julia is both a blessing and a curse. It makes it easy to write high level code, but it can make low-level library code hard to write in a generic fashion.
This appears to be the only function that is 1-based indexing instead of 0-based?