illustrative abstractions

0%

C++ Notes Series (No. 1) Package Principles and Namespaces

Introduction

In computer programming, package principles are a way of organizing classes in larger systems to make them more organized and manageable. They aid in understanding which classes should go into which packages (package cohesion) and how these packages should relate with one another (package coupling). Package principles also includes software package metrics, which help to quantify the dependency structure, giving different and/or more precise insights into the overall structure of classes and packages.

An important counterpart of which is namespace in C++. CPPReference states that

Namespaces provide a method for preventing name conflicts in large projects.

Symbols declared inside a namespace block are placed in a named scope that prevents them from being mistaken for identically-named symbols in other scopes.

Multiple namespace blocks with the same name are allowed. All declarations within those blocks are declared in the named scope.

Discussion on functions in namespaces or classes

Putting an isolate function in a namespace could be rather a better decision than incorporating it in a class as a method, contradicting to what we have learnt from COMP0004. More specifically, whenever you can implement some functionality efficiently without having to access any private or protected code or data members, you should break it into a free function in the class’s namespace instead of leaving it as a member function. The reason is that by doing so, you keep the class’s interface as small as possible, and thereby reduce the amount of code that potentially needs to be changed if you change the private internals of the class, which is the point of Objective Oriented Programming (OOP) in the first place. Scott Meyers, author of Effective C++, goes into more detail here.

Unfortunately, separating out code that works on T from the class T itself just feels untidy to many programmers raised on the OOP mantra of “Bring code and data together”. But “bringing code and data together” doesn’t actually achieve anything material from a code maintenance or expressiveness point of view — all it gets you is a certain aesthetic appeal, so if you can get past that, you will benefit from the materially better design that comes from keeping class interfaces as small as possible.

If it takes a while to convince yourself that separate functions are actually the Right Thing, don’t feel bad — Meyers’s own first edition of Effective C++ made the same mistake. An example of the C++ Standard Library getting it wrong would be a function like find_first_of() in std::string, which can be implemented with full efficiency without having to know any of the internal details of a std::string — all such a function needs is access to the public functions size() and operator[]().

To end with Scott Meyers own paragraph,

It’s time to abandon the traditional, but inaccurate, ideas of what it means to be object-oriented. Are you a true encapsulation believer? If so, I know you’ll embrace non-friend non-member functions with the fervor they deserve.