Dependencies

A Boost library does not generally depend on other libraries, except for Boost or the C++ Standard Library. There are some exceptions. For example, Boost.Iostreams, and Boost.Beast, have an optional dependency on zlib, to provide support for gzip and zlib compression and decompression. If zlib is not available, Boost.Iostreams will still work, but without the ability to handle gzip and zlib formats. Another example is Boost.Asio, which has an optional dependency on OpenSSL, to provide support for SSL and TLS protocols. These protocols are widely used for secure network communications. Again, if OpenSSL is not available, Boost.Asio will still work, but without support for SSL or TLS.

Other examples include Boost.Python interfaces with the Python C API, so obviously depends on a Python installation. Boost.Locale depends on the International Components for Unicode (ICU) to provide Unicode and localization support. On Unix systems, Boost.Thread relies on the pthread library. Boost.Compute has a dependency on OpenCL.

For other libraries that you might want to take a dependency on, get a discussion going first with the Boost developers' mailing list. The general rule is avoid unreasonable dependencies.

Benefits and Effects of Coupling

A Boost library should use other Boost Libraries, or the C++ Standard Library, when the benefits outweigh the costs. In general, Boost libraries are designed to be as independent as possible, so that users can pick and choose the libraries they need without being forced to include unnecessary code. Many Boost libraries are indeed standalone and can be used separately without any dependencies on other libraries.

The benefits of using components from other libraries may include clearer, more understandable code, reduced development and maintenance costs, and the assurance which comes from reusing well-known and trusted building blocks. The costs may include undesirable coupling between components, and added compilation and runtime costs. If the interface to the additional component is complex, using it may make code less readable, and thus actually increase development and maintenance costs.

Negative effects of coupling become obvious when one library uses a second library which uses a third, and so on. The worst form of coupling requires the user understand each of the coupled libraries. Coupling may also reduce the portability of a library - even in cases when all used libraries are self-sufficient (see Examples of Questionable Dependencies).

Examples of Acceptable Dependencies

The Boost.Graph library depends on Boost.Iterator and Boost.PropertyMap. Similarly, Boost.Asio, mentioned above, depends on several other Boost libraries including Boost.System, Boost.DateTime, and Boost.Bind, and others. Boost.Asio itself is recommended if your library needs networking.

A good example where another boost component should certainly be used is Boost.Core, as it has considerable benefits; it simplifies code, improves readability, and signals intent. Boost.Core contains small utilities, usually polyfills for standard components, which you use when targeting C++ standards where they are not available. Costs are low as coupling is limited; the Boost.Core header includes only lightweight headers. There are no runtime costs at all. With costs so low and benefits so high, other boost libraries should use Boost.Core when the need arises.

Other Boost libraries you might consider as good foundational components include:

  • Boost.Compatibility has been updated recently and has a similar role to Boost.Core. Its' classes provide polyfills from std classes, and have no extensions.

  • Boost.Config is used by almost all libraries. It provides macro definitions to make your code portable. It enables you to detect standard levels prior to C++17, to check which platform/compiler you are building for, and to add the relevant platform-specific code to create compiled libraries.

  • Boost.Assert is in general recommended over plain <cassert>, as it provides a source_location polyfill. Boost.Assert is used by almost all Boost libraries, so using it makes your library more interoperable with the others.

  • Similarly, Boost.ThrowException is in general recommended over plainly throwing exceptions, as it adds more info to the thrown exceptions and makes behavior more configurable. As it too is widely used in exiting Boost libraries, good interoperability applies.

  • Boost.Utility includes several non-templated, non-data structure related classes and functions, such as base-from-member idiom, checked delete, next and prior functions, noncopyable, and result_of.

  • Boost.ConceptCheck provides tools for specifying and checking that types meet the requirements of generic algorithms. It’s used by many other libraries to ensure that template parameters meet the necessary requirements.

  • For handling data types and structures, one of Boost.FunctionTypes, Boost.Fusion, Boost.Any, Boost.Variant, or Boost.Variant2 might provide what you need.

  • As well as supporting data types, Boost.Variant2 is preferred over std::variant, as it enforces better invariants and is never valueless, unlike is standard counterpart.

  • For metaprogramming, Boost.Mp11 is the latest metaprogramming library and provides many of the building blocks for this style of programming. Boost.Mp11 should be used in preference over the older Boost.Mpl and Boost.Preprocessor.

  • Boost.Describe is valuable if you need reflection as part of your interface, which will occur when your library users are passing in user-defined types for your library to process.

Examples of Questionable Dependencies

An example where another Boost component should not be used is simply where the use of the library is minimal, and does not justify the cost of having the dependency. Or perhaps when a C++ Standard Library has the same functionality for a lower cost.

Other examples of questionable dependencies, outside of Boost, include libraries with unstable interfaces (libraries that change frequently), libraries that are platform-specific, not widely supported, not public, or are internal in some way. Obviously libraries with heavy runtime requirements should largely be avoided altogether.