Shims: A Benign Imposter

Shims analogy

Shim is basically a piece of wool/wood/other material which is placed in between two objects to make them fit better. Remember how you fixed that wobbly table?

In computer engineering context, a shim is a lightweight program which intercepts requests, potentially modifies it and redirects to the right service. It sounds like a middleman, which it is, but additionally, there’s no change in the request you make, which means the interception is transparent - a “benign imposter”.

Let’s look at an example.

Shims in pyenv: An example

If you’ve used python, and used it extensively enough, you might have come across issues with switching python versions. You want to use different python versions for different projects. Also you want to isolate the python dependencies of different projects.

This is where pyenv comes in - it allows you to switch between different python versions. Let’s look at some examples:

If you notice the location of python executable above, it points to /Users/<user>/.pyenv/shims/python. How is shims getting used here?

Understanding PATH

when you execute a command like python or ls in the command line, the executable is searched in a list of directories given by the PATH variable. The earlier directories are searched first.

How pyenv uses PATH

pyenv puts the shims at the start of the PATH. Such that any call to say python will be intercepted by the shim called python, rather than actual system python.

PATH=$(pyenv root)/shims:/usr/local/bin:/usr/bin:/bin
  1. At a high level, pyenv shims (like /Users/<user>/.pyenv/shims/python) are inserted at the start of PATH environment variable.
  2. The shim (in this case the “python” shim) can then intercept the command, and pass it to pyenv.
  3. From here on, pyenv can decide which python version is currently activated. There are certain rules it uses, but we can think of it as the version we activated using the pyenv local. This information is stored in $(pyenv root)/version.
  4. Then pyenv passed the command to the right executable (python executable in /Users/<user>/.pyenv/shims/versions/3.9.5/ etc.).
  5. Shims for pip work in a similar way.

Concluding notes

pyenv uses shims to seamlessly switch between different versions of python. With pyenv different projects can have different python versions at the same time (using pyenv). This might remind you of the proxy pattern (the requests are forwarded to the right version depending on how the project is configured.)

Another common use of shim is to support newer APIs on older specifications/executables. Note that like a true middleman, shim can adapt the request or response. In this sense, shim acts as an example of adapter pattern.