---
# System prepended metadata

title: Dependency resolution

---

# Dependency resolution and mutual recursion

Recursion can be tricky to get your mind around, but satisfying once you do. I recently stumbled upon a problem for which a kind of *mutual* recursion turned out to be the simplest solution. It took me a moment to figure out (because I found it even more brain-bendy than "normal" recursion), but I was glad once I did. I hope you enjoy it as much as I do.

## The (simpler) problem

Let's start with a simple version of the problem, for which (normal) recursion is sufficient.

Suppose we're trying to write a dependency resolution algorithm. My package (or more generally, *artifact*) depends on specific versions of some others — which, in turn, depend on others, etc. We want to collect the set of ALL transitive dependenices (the "transitive closure").

A simple way to do this is with a depth-first traversal. The skeleton would look like this:

```
def resolve(Artifact a): Set[Artifact] {
  Set deps  // Collect all deps here
  for (dep in a.deps) {
    deps += resolve(dep)
  }
  return deps
}
```

Of course, this doesn't handle error cases. For example, we should fail if there's a conflict (e.g., I depend on Foo 1.1, but I also depend on something else that requires Foo 1.2). We can accomplish that by keeping track of accumulated dependencies instead of returning it as a set:

```
def resolve(Artifact a, Set[Artifact] acc) {
  if (a.name in acc and a.version doesn't match)
    throw DependencyResolutionError
  else
    acc += a
  
  for (dep in a.deps) {
    resolve(dep, acc)
  }
}
```

We can also add a helper method for the user:

```
def resolve(Artifact a): Set[Artifact] {
  Set acc = Set.empty
  resolve(a, acc)
  return acc
}
```


## The (more fun) problem

In the simple version, we depend on only one version of each artifact. But what if multiple versions are allowed? E.g., what if I can depend on `Foo 1.x`?

Suppose my artifact has three dependencies: `Foo 1.x`, `Bar 1.x`, `Baz 1.x`. And suppose there are three such version of `Foo`, four of `Bar`, and five of `Baz`. Then I potentially have to try 3 * 4 * 5 = 60 combinations to see if there's a good completion.

One way to do this would be to iterate over all 60 such tuples (x, y, z) and do a depth-first traversal for each. It may be tempting to try it like this:

```
def resolve(Artifact a, Set[Artifact] acc) {
  if (a.name in acc and a.version doesn't match)
    throw DependencyResolutionError
  else
    acc += a
    
  // Generate all tuples ((x1, y1, z1), (x1, y1, z2), ...)
  // Perhaps do it in a lazy way, to save time and space.
  List[List[Artifacts]] depsList = ...
  
  for (deps in depsList) {
    for (dep in deps) {
      resolve(dep, acc)
    }
  }
}
```

But this gets ugly quickly. Not only do we need to catch exceptions, but we need to unwind `acc` to recover from those failed searches. Moreover, we shouldn't just blindly continue down the list of tuples. If resolution of `x1` throws while resolving `(x1, y1, z1)`, we shouldn't continue trying `(x1, y1, z2)` etc. We need something smarter.

An alternative is to use recursion again. Instead of explicitly enumerating all tuples, we call a function to handle (all possible choices for) the first element of the tuple, and it is responsible for invoking the function on the second element, etc. 


```
def resolve(a: Artifact, acc: Set[Artifact]): Set[Artifact] {
  if (a.name in acc and a.version doesn't match)
    throw DependencyResolutionError
  else
    acc += a

 return a + walkChildren(a.deps, 0, acc + a)
}

def walkChildren(children: List[List[Artifact]], i: Int, acc: Set[Artifact]): Set[Artifact] {
  if (i >= children.length) return Set.empty

  for (child in children[i]) {
    res = resolve(child, acc)
    return res + walkChildren(children, i+1, acc + res)
  }
}
```

