Monday, January 11, 2021

Moving Conversion from Caller to Callee

Consider this: you are maintaining a C++ codebase which uses strings. You have some lower-level methods which take/use C-style string, and you have some higher-level methods which use a string wrapper type (we'll use std::string for example purposes). Let's say you're going to convert the lower level code from direct pointers to something like std::string_view.

In the above case, there is an automatic conversion, re both types being in the std library, so everything just works. But, if you have a large codebase, you have other string types (MFC, other), which may not automatically convert. You may end up writing some inline conversion to call the methods, or you may end up writing some wrapper methods to do the conversion at the call site. Both of these, though, are sub-optimal: the lower-level method is taking a logical string, and there shouldn't need to be additional intellectual or code burden at the call site to convert from one logical string type to another.

Enter "as_[type]" (eg: "as_string_view", or "as_zstring_view"). These are conceptual types, derived from the base desired types, which simply implement conversion methods (eg: constructors) from the other logically equivalent types in your codebase. Used appropriately, these can simplify the usage of the methods, while allowing seamless conversion of lower-level code to use new (but logically equivalent) data types.

(As a potentially more real-world example, consider "as_span<const BYTE>", which can accept a std::vector, or a std::string, and interpret both as a logical span of BYTEs. This can eliminate some extraneous overrides, and simply code usage, in places where it is applicable.)