I want to use a simple optimization of an univariate function in my package DistributionFits.jl, but I want to avoid the package dependency on the heavy-weight package Optim.jl.
So far, I tried implementing Dependency inversion by considering function
optimize to be an interface defined in
DistributionFits.jl. The user of the package then needs to assign a concrete function to the binding
DistributionFits.optimize by using exported function
set_optimize(f_optimize). Hence, I could remove Optim.jl from the package dependencies.
In addition, Requires.jl allows to invoke set_optimize(Optim.optimize) automatically when the module using DistributionFits is also using Optim.jl.
Is this a good Julian way to avoid hevay package dependencies?
Does this approach protect my package and further dependents from the need of being recompiled after changes in some other aspect of Optim.jl?
After reading this mulitple implementations answer by @stevengj, I implemented a slightly more complex strategy. Using a type hierarchy allows the “interface” to comprise more than a single method.
I now have a method
optimize(f, ::AbstractDistributionFitOptimizer, lower, upper) that calls the actual optimization routine. By specializing this method, different implementations can be used.
DistributionFits.set_optimizer(::AbstractDistributionFitOptimizer) configures the Optimizer used by the package.
Again, Requires.jl is used to automatically set the default, if the Optim.jl package is in scope.
I am happy about critical feedback and advice on a Julian way of managing project dependencies in a way that higher-level code does not depend on lower-level code.