Using Dependency inversion to avoid depending on volatile/heavy packages

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?

Related posts

1 Like

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.
Method 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.