Folders: What? Why? How? How exactly? Why so many?
Why so many folders? Because:
The more the better, up to a point, of course...
- They help us find things in ~Olog(n) rather than O(n)...
1) - They help avoid filename clashes, just like namespaces help avoid name clashes.
What?
The name of each folder is usually reflected in a corresponding namespace, same spelling, same case. To avoid confusion, the folders in the workspace (”solution”) panel precisely mirror the real folders structure.
How?
If you’re not sure where a new package should go, discuss it with us in the Forum. A lot of thought has gone into the present structure, and a lot of thought should go into keeping to the spirit of it.
How exactly?
Well, it’s a long story. Folders are good to assemble tree structures, just like hierarchies. But there are many ways of looking at software, and many ways to visualize hierarchies into it; and the folder structure can only reflect one hierarchical view of the thing.
One completely useless first idea that might occur to all of us, at first, is trying to reflect inheritance hierarchies. If you think about it, though, you’ll see why this makes no sense whatsoever:
First of all, the most abstract classes would be near the root folder, while the bottom (most derived) classes would be deeply buried in sub-sub-sub-sub-folders... Ironically, the concrete classes are the ones that you need to refer to often, while the abstract class may only be needed once in a while to define a polymorphic reference or pointer.
Secondly, tall inheritance trees are seldom used; and when they are, they often involve multiple inheritance, which a folder hierarchy would not be able to reflect.
What then?
The most suitable candidate hierarchical view of software for folder structure definition is “chain of command”. Just like in an army, functions call other functions, which in turn call other functions... You can visualize this as main() being the top dog, and functions that call no further functions as being the foot-soldiers.
But a function may be called by more than one function!
Indeed. The “chain of command” metaphore doesn’t go very far, –luckily... Otherwise our folder tree would be too deep.
If a function is “very public” (has lots of callers) it will probably be in some top-level folder. Only functions that are slaves (fully owned) by some class, module or package, will be found in a subfolder thereof.
But the files in the folders usually define whole classes, not just “functions”!
Indeed. And luckily so: This means that a function that is called from several other functions, may still be in a sub-folder if all those functions that call it are part of the class, classes or files in the folder above. You could say that the function is a slave of the package above it.
But what if class A has a function that calls a function of class B, AND viceversa?
That would be spaghetti code, which indeed this folder system helps diagnose and elliminate. Classes should relate to each other “chain of command”-wise in one direction only.
What happens if a class is instanced inside another?
Usually the containing class calls the shots.
What happens with inheritance?
Derived classes rule. This may be a surprise, but derived classes are top dogs relative to the classes they inherit. Think of it this way: Whose functions override whose?
So, abstract classes go in sub-folders?
Depends. If an abstract class is inherited by many other classes, and is used to define polymorphic pointers and references, then, obviously, it should have exposure (sit at a shallow level in the folder tree). But if inheritance is only being used as an orderly concept-building device, and is a private matter of a specific package, then, indeed, that abstract class should probably reside in a sub-folder.
Ok, what do you do when you have a tall hierarchy, with multiple inheritance, and the whole shabang?
I cheat ...
... I put all of the files defining all of the classes in that hierarchy, in the same folder; and make sure that folder is in the (top level) “hierarchies” folder. That’s indeed cheating, but better than the alternatives. And it makes sense from the point of view that it keeps closely related things together. It also makes sense in the sense that classes in a large hierarchy usually have a lot in common... It allows us to place slave classes and functions common to many of them under subfolers of that hierarchy’s folder.
Doesn’t that imply that there’d be a “hierarchies” namespace?
Actually, no; that’s an exception to the rule: The top two levels of folders do NOT have associated namespaces. Top level folders are either “project” folders (for lib, dll or exe targets), or else library wrappers, header-only libraries, etc; –not a part of the “chain of command” representation. Second level folders are classification folders within project targets, such as “/sub/”, a folder named “sub” because it contains packages that are common packages to packages on the public interface, but are not themselves part of the public interface. Or “/iface/”, which contains the public interface packages. As well as “/hierarchies/”, “/test/”, etceteras. Note, however, that we often use the term “top level folder” to refer to third-level folders –i.e.: “top level” within their classification and project.
Where’s the “include” folder?
We don’t have one. Each package folder contains the public interface header file for that package. But there’s also a header file in the “/iface/” folder under each project, named “<project-name>.h”, which includes all the headers of all the packages under “/iface/”, for that project.
Do folders relate to header inclusion strategies?
Absolutely! The “chain of command” graph –with top dogs on top– is, in many ways, a vertical-flip mirror image of the “header inclusion” graph. Thus the first rule below. The rest of the rules allow for shared headers. These are the rules:
- A header file may safely include header files in sub-folders.
- A header file anywhere may also include a header file from:
- a top-level folder under “/sub/”, within the same project.
- a top-level folder under “/hierarchies/” in the same project.
- a top-level folder under the “/hpp/” top-level folder (true top-level, –header-only libraries)
- a top-level folder under the “/thrdsafe/” top-level folder (true top-level, –thread-safe libraries)
- the “/iface/” folder of another project, if that other project is a thread-safe lib or dll/so
This doesn’t in any way negate the requirement that headers should only include other headers when it’s absolutely necessary and inescapable. Whenever possible, header files should use pointers or references to types forward declared within the deepest curly brace block possible, and defer header inclusion to the .cpp file. Which is the reason behind the rule that all public interface classes must be pimpl’s: Public interfaces are often included by other header files, and therefore they should be under the highest pressure to keep inclusion of yet-other-headers to the bare minimum.


