Why Enumerators
Look at both of these function calls and see which one you think is the most readable:
fileSystem->ListFiles( fileSystem->GetCurrentDirectory().c_str(), files, filePattern, true );
And
fileSystem->ListFiles( fileSystem->GetCurrentDirectory().c_str(), files, filePattern, FS_SEARCH_RECURSIVE );
They are equal except for the second example using an enum value instead of a boolean as the last parameter. You can see from reading the function call that the second will search recursively for files.
The first example passes a parameter true which could mean anything, and you can't be certain of the meaning of this parameter changes unless you check the declaration each time you read the code.
Clearly the one using an enum is easier to read and does not require us to look up the declaration to understand the behavior of the function. The drawback from using enums is that for each function call where you usually would be using a boolean parameter you will have to create an enum with the valid enum values that can be passed in to the function.
This is the original function declaration:
bool ListFiles( const char* path, fileList_t& out, const char* pattern = "*", bool recursive = false ) const;
Looking at a convention where we always define the enumerator together with the function it might look like this:
enum listFilesRecursive_t { FS_SEARCH_NON_RECURSIVE, FS_SEARCH_RECURSIVE }; bool ListFiles( const char* path, fileList_t& out, const char* pattern = "*", listFilesRecursive_t recursive = FS_SEARCH_NON_RECURSIVE ) const;
Conclusion
Although it might become overly time-consuming to create and use enums for function parameters instead of booleans, especially when code is in constant change it still has some advantages:
- Immediate readability of the meaning of the parameter by just looking at the function call (assuming reasonable enum names are used...).
- More explicit description of the parameter not only at the declaration because of the parameter being its own type, but wherever it is used as the compile will error out unless a valid enum value is used.
We should be very careful with naming of enums that could be too general which could lead to naming collisions, especially those in global scope.