Figuring out good names for functions can be hard, as they need to be long enough to describe what the function does without being so wordy that nobody wants to type them. Accessor functions in particular should be short and sharp so that it is clear what they do when they are used in code.

A convention that we came up with at a former workplace was name the accessor functions based on how much processing they did to return the desired value. Functions which do no processing return the data As something, whereas other functions transform the data To something else. This indicates to the user of the class what the expected runtime cost of the function is likely to be so they can make a design decision on how to consume the data.

To expand on this, the guideline is to name the function “as something” when it is returning:

  • the value by reference or const-reference like a traditional getter,
  • a view or span of the data,
  • another type which the data can be transformed to easily and efficiently.

Otherwise name the function “to something” when it:

  • needs to allocate memory,
  • performs a time-consuming transformation on the data,
  • the returned value bears little to no resemblance to the original data.

Here is an example where we have a name object that stores a string inside it, functions which return a reference or a view of the string are as something, whereas the functions which compute the hash value or allocate memory are to something.

class ExampleName
{
	std::string value_;
public:
	// Traditional 'get' function
	const std::string& as_string() const { return value_; }

	// Cheap accessor function
	std::string_view as_string_view() const { return value_; }

	// More expensive converter function
	uint64_t to_hash() const; // Computes hash of string in cpp file

	// Accessor function which copies the data
	std::string to_string() const { return value_; }
};

Here is another example of a fixed point class which has functions to return the data as a different type.

class FixedPointNumber
{
	int32_t integer_;
	uint32_t fraction_;
public:
	// Quick arithmetic conversion to floating point
	double as_double() const
	{
		return integer_ + static_cast<double>(fraction_) / std::numeric_limits<uint32_t>::max();
	}

	// Allocates memory for variable width object
	BigDecimal to_decimal() const;
};

In this case the function that converts to a floating point type is called as_double because it only uses simple constant-time operations to do the conversion. Whereas the function called to_decimal can allocate and has a variable runtime cost associated with the conversion.

Note that this works best in classes which represent a single logical value.