Should I create problem-specific type aliases?

Frequently, I settle for a general-purpose type when I really want a problem specific one. For example, I might choose int when I really want an id_number that shouldn't support arithmetic, or choose std::map<int, std::string> when an ideal type would express a problem-specific invariant.

A general-purpose approach is often the best choice because the cost of writing a special-purpose type is far too high to be justified by the problem's scope.

As an alternative, I could loosely hint at the domain-specific meaning of a more general type by giving it an alias:
1
2
3
using symbol = int;
using bitcode = std::string;
using bitcode_table = std::map<symbol, bitcode>;

However, I do not typically do this: these force the programmer to remember the real type beneath the alias, and otherwise serve only as comments with no associated semantics.

I also also found the cost of looking up the definition of a name frequently exceeds the benefit it provides - such code often feels over-factored.

Some style guides recommend creating these kinds of aliases. Am I correct to avoid them? If not, do you create them in your own code base? If so, when?

Thanks :)
Last edited on
Dear mbozzi

I sometimes think about the same thing. In the old-fashioned manner, it was realized by macro such as Win32 type(DWORD etc). Modern c++ enables the same utility by using sentence(probably for the restriction to a defined scope)
Thus, I suppose that there is some concrete reason. I also want to hear experts opinions, just my use case of general-purpose type.
(1)precision or size of primitive type
real number precision(float, double or multi-precision) is easily switched by definition change. char, short or int are the same discussion.

(2) avoidance of long name, particularly STL containers
map,unordered_map etc entails long name due to template arguments. Its iterator or so becomes so long name, general-purpose type avoids it.

(3) test of developing class
when developing new class, it is convenient to easily switch testing coding types easily.

In anyway, this is merely my opinion. I also hear other opinions or concensus experts settled.

Kind regards


At work, we have "jobs" and "users" and "documents" etc. They're all identified by a number, and so we have common typedefs for job_no, user_no, doc_no, etc. These help to express the intent of a variable. Also, because they are so common, everyone knows what job_no means.

I think it's okay if the aliased type is widely used and you can expect everyone to know what the underlying type is. In this case, the alias indicates the intention of the variable. It's probably also okay if the alias is localized to a file or a function.

What you don't want to do is define a strange alias for every obscure type used by random classes. As you said, in that case the benefit isn't worth the cost of having to go chase down the actual type.

Hope this helps.
I am not a fan. For plain types, it serves no purpose; all it does is create what we call 'tribal knowledge' which means the only way you can know what is going on is to be a member of the tribe and have memorized the extra useless cross reference.

for not plain types, there are merits. In the old days for sure a named type like colors that was really an array of 3 or 4 unsigned char representing rgb or rgba had merits. Today? Maybe not. We have a lot more tools than plain old arrays now.

that leaves us the 'grey area'. you could make a simple class or struct for some type that is going to be heavily used, and its likely to end up getting quality of life methods and operators as it grows up. But, in many cases, just a vector or tuple or similar container is all you needed, but you use it a lot. A common theme here is a 2d matrix... it gets really old saying vector<vector<complex<double> > > and giving that a named type to mask the annoying syntax may be all you needed to do. If you have something like that, putting a name on it is worthwhile. I guess if I made a rule for making a named type from a standard type, it would be that the named type has to hide more than one set of brackets (of any type).
At work, we have "jobs" and "users" and "documents" etc. They're all identified by a number, and so we have common typedefs for job_no, user_no, doc_no, etc. Also, because they are so common, everyone knows what job_no means.
Sounds normal. job_no has become part of your product's library - part of the language that your team uses to discuss the product. Like you said, it's only aliases for every tiny little thing that cause problems.

It occurs to me that when I look at a variable type, I expect to learn the variable's domain - the set of values it can contain - and the operations supported on it. I do not expect to learn what the variable's used for - the variable name is responsible for that.

If I want to document some special invariant I have assert in the toolbox, which I guess is acceptable, if ugly. I should consider writing more assertions.

But, in many cases, just a vector or tuple or similar container is all you needed, but you use it a lot. A common theme here is a 2d matrix... it gets really old saying vector<vector<complex<double> > > and giving that a named type to mask the annoying syntax may be all you needed to do. If you have something like that, putting a name on it is worthwhile.

I think abbreviations are probably okay. Give it a mnemonic name, maybe something like
using vec_2d_complex = std::vector<std::vector<std::complex<double>>>
So hopefully most programmers can still can understand the type, or at least remember it.

Topic archived. No new replies allowed.