# Dependency injection in Julia

**URL:** <https://discourse.julialang.org/t/dependency-injection-in-julia/12026>\
**Category:** General Usage\
**Created:** [June 28, 2018, 8:09am UTC](https://discourse.julialang.org/t/dependency-injection-in-julia/12026 "2018-06-28T08:09:12Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![essenciary](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/essenciary/32/210469_2.png) [@essenciary](https://discourse.julialang.org/u/essenciary)\
**Post date:** [June 28, 2018, 8:09am UTC](https://discourse.julialang.org/t/dependency-injection-in-julia/12026/1 "2018-06-28T08:09:12Z")

</div>

Wondering if anybody found a good way to implement dependency injection in Julia. I have many situations where I use “adapters”: take for instance a `Database` module which uses various adapters (MySQL, SQLite, Postgres, etc).

And what I usually end up with is:

- a `const` in the module global scope which references the adapter
- a lot of `eval` statements in the line of:

```julia
if haskey(SearchLight.config.db_config_settings, "adapter") && SearchLight.config.db_config_settings["adapter"] != nothing
  db_adapter = Symbol(SearchLight.config.db_config_settings["adapter"] * "DatabaseAdapter")

  include("database_adapters/$(db_adapter).jl")
  Core.eval(@ __MODULE__ , :(using .$db_adapter))
  Core.eval(@ __MODULE__ , :(const DatabaseAdapter = $db_adapter))
  Core.eval(@ __MODULE__ , :(export DatabaseAdapter))
else
  const DatabaseAdapter = Nothing
end

```

Looks like a code smell to me.

I think a nice solution would be to have a mechanism to pass arguments when `using` a module, in the line of:  
`using Database(adapter = MySQLAdapter)`

---

<div class="post-metadata">

**Author:** ![quinnj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/quinnj/32/11_2.png) [@quinnj](https://discourse.julialang.org/u/quinnj)\
**Post date:** [July 2, 2018, 4:06pm UTC](https://discourse.julialang.org/t/dependency-injection-in-julia/12026/2 "2018-07-02T16:06:16Z")

</div>

I think a more Julian approach would be to utilize a kind of `DataBaseAdapter` interface and rely on the caller to call setup appropriately; something like:

```julia
module Adapters

abstract type Adapter end

"Subtype must define `connect!(x::MyAdapter)` to satisfy interface"
function connect! end

"Subtype must define `query(x::MyAdapter)` to satisfy interface"
function query end

end

module AdapterAs

import Adapters

struct AdapterA
end

Adapters.connect!(::AdapterA) = # ...
Adapters.query(::AdapterA) = # ...

end

module App

import Adapters

const ADAPTER = Ref{Adapter}()

function setadapter!(x::Adapter)
    ADAPTER[] = x
end

function query(sql::String)
    Adapters.connect!(ADAPTER[])
    Adapters.query(ADAPTER[])
end

end

```

With this kind of setup, you leave it to the driving application or script to call `import AdapterAs` and `App.setadapter!`, or potentially `import AdapterBs` if there was an alternative adapter they wished to use.

---

<div class="post-metadata">

**Author:** ![o314](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/o314/32/252_2.png) [@o314](https://discourse.julialang.org/u/o314)\
**Post date:** [July 3, 2018, 2:48am UTC](https://discourse.julialang.org/t/dependency-injection-in-julia/12026/3 "2018-07-03T02:48:52Z")

</div>

1. Naming is a bit hacky. I would try to slim it.
2. I would try to factorize by parametrizing as mush as i can (see below)
3. otherwise not a bad pattern

```julia
# parametrizable with (conf section=="DB")

if haskey(FOO.config.db, "driver") && FOO.config.db["driver"] != nothing # todo parametrize config section "db"
    driver = Symbol(FOO.config.db["driver"] * "DbDriver") # parametrize julia type suffix

    include("db/$(driver).jl") # parametrize directory
    Core.eval(@ __MODULE__ , :(using .$driver))
    Core.eval(@ __MODULE__ , :(const DbDriver = $driver)) # parametrize julia type suffix (see previous one)
    Core.eval(@ __MODULE__ , :(export DbDriver)) # idem
else
    const DbDriver = Nothing # idem
end

```

---

<div class="post-metadata">

**Author:** ![tk3369](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tk3369/32/2824_2.png) [@tk3369](https://discourse.julialang.org/u/tk3369)\
**Post date:** [July 3, 2018, 1:50pm UTC](https://discourse.julialang.org/t/dependency-injection-in-julia/12026/4 "2018-07-03T13:50:04Z")

</div>

Another reason for reviving DBAPI? 😉

---

<div class="post-metadata">

**Author:** ![essenciary](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/essenciary/32/210469_2.png) [@essenciary](https://discourse.julialang.org/u/essenciary)\
**Post date:** [August 23, 2018, 1:12pm UTC](https://discourse.julialang.org/t/dependency-injection-in-julia/12026/5 "2018-08-23T13:12:25Z")

</div>

Thanks

I’m actually happy with the naming. Must not forget that this is not user code, but framework code. It’s not meant to be typed by the users of the library (they just need to define the config `Dict`). In such cases (write once, read multiple times) I prefer to err on the side of readability.

---

<div class="post-metadata">

**Author:** ![essenciary](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/essenciary/32/210469_2.png) [@essenciary](https://discourse.julialang.org/u/essenciary)\
**Post date:** [August 23, 2018, 1:16pm UTC](https://discourse.julialang.org/t/dependency-injection-in-julia/12026/6 "2018-08-23T13:16:07Z")

</div>

Wouldn’t that just move the problem somewhere else?

Also, curious if there’s any solution for

1. defining optional dependencies (right now I have to make `SQLite.jl`, `MySQL.jl` and `PgLib.jl` explicit dependencies of my package forcing users to install all, even if they’ll only use one backend).
2. creating a plugins system where a 3rd party user can extend my library and add their own dependencies (like in this case, somebody plugging in a MariaDB adapter with its dependency on an a `MariaDB.jl`)

For @kristoffer.carlsson 🙂

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [August 23, 2018, 1:24pm UTC](https://discourse.julialang.org/t/dependency-injection-in-julia/12026/7 "2018-08-23T13:24:55Z")

</div>

You can use `Requires.jl` for some of that.

---

<div class="post-metadata">

**Author:** ![essenciary](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/essenciary/32/210469_2.png) [@essenciary](https://discourse.julialang.org/u/essenciary)\
**Post date:** [August 23, 2018, 1:58pm UTC](https://discourse.julialang.org/t/dependency-injection-in-julia/12026/8 "2018-08-23T13:58:14Z")

</div>

@kristoffer.carlsson Cool, thanks - let me give it a try.

---

<div class="post-metadata">

**Author:** ![o314](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/o314/32/252_2.png) [@o314](https://discourse.julialang.org/u/o314)\
**Post date:** [August 27, 2018, 3:11am UTC](https://discourse.julialang.org/t/dependency-injection-in-julia/12026/9 "2018-08-27T03:11:18Z")

</div>

Naming can be very subjective, so i will not try to defend one vs another. My purpose was to reduce variations without real functionality eg. noise to better allow factorization of function. If you feel it works well. That’s ok.

My understanding is that it is not only a problem of user vs admin. But a problem of toolchain selection.  
A choice not only made by one person and forever. It can be very wide and open.

Do you know the backend selection used by Plots.jl @ [Plots.jl/backends.jl at v0.19.3 · JuliaPlots/Plots.jl · GitHub](https://github.com/JuliaPlots/Plots.jl/tree/v0.19.3/src/backends.jl)

`Requires.jl` can help to load different pkg on the fly.  
`Plots.jl` has some good tracks to store choices and handle tiny workflow to make them callable.

---

<div class="post-metadata">

**Author:** ![essenciary](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/essenciary/32/210469_2.png) [@essenciary](https://discourse.julialang.org/u/essenciary)\
**Post date:** [August 27, 2018, 9:16am UTC](https://discourse.julialang.org/t/dependency-injection-in-julia/12026/10 "2018-08-27T09:16:18Z")

</div>

Definitely:

> There are only two hard things in Computer Science: cache invalidation and naming things.  
> – Phil Karlton

What I meant was that the above code was “private”. The user would just say `driver = MySQL`.

Yes, the `Plots.jl` backends analogy is exactly what I have in mind. I don’t want to comment yet as I still have to test `Requires.jl` (although deep in my heart I have the feeling that `Pkg` will complain if the dependencies are not explicitly declared and installed – and that users won’t be able to add new “backends” on the fly without changing the `Project.toml` of the original package).
