typedef Morality

C

cppaddict

Hi,

I recently started using typedefs and am curious if they are ever
considered evil.

In particular, I'm thinking of a situation where a typedef is used in
a file but defined in another, included file. Someone reading the
code might have to track down the original definition to make sense of
the code, and thus it reduces readability.

I didn't find anything int the C++ FAQ denouncing typedefs, though, so
I'm guessing they're not considered bad form. Anyone have thoughts on
the subject?

Thanks,
cpp
 
P

Phlip

cppaddict said:
I recently started using typedefs and am curious if they are ever
considered evil.

They are good. Code should follow Don't Repeat Yourself. That rule's most
important for behavior (the stuff inside {} on methods). Consider types as
structure, which is less important to not duplicate, but every little bit
helps. For example:

typedef std::map<string, string> params_t;

bool
Product(params_t & testCase)
{
double num (strtod(testCase["Input1"].c_str(), NULL));
double den (strtod(testCase["Input2"].c_str(), NULL));
double quo (strtod(testCase["Product()" ].c_str(), NULL));

return num * den == quo;
}

I'm about to fold the lines that generally say double quo
(strtod(testCase["Product()" ].c_str(), NULL)); into a single reuseful
function. When I do, the typedef params_t will appear in its arguments. This
lets us upgrade params_t in only one place, and not write all the
std::map<etc etc> all over the place.

Further, the exact point where a template instantiates into a class tends to
conjoin that template with the types seen at the instantiation point.
Repeating std::map<etc etc> all over the place could generate subtle
differences between each instance, so instantiating with a typedef reduces
this risk, and instantiating in a header reduces it more. (It can't
eliminate it though, because users could #include their headers in any
order.)
In particular, I'm thinking of a situation where a typedef is used in
a file but defined in another, included file. Someone reading the
code might have to track down the original definition to make sense of
the code, and thus it reduces readability.

There are many ways to reduce readability by stretching out modules, so
their declarations are far away from their definitions, both physically and
cognitively far. To promote readability, write simple code in short methods,
and give everything the narrowest scope possible. If another module
somewhere needs a std::map<string, string>, I would _not_ put params_t into
a header that both its modules can see. I would write another typedef in
that module, with a different name.

Naming things after what their intent always helps readability. params_t
intends to store parameters to methods, as maps of strings. Another module
would name their typedef differently.

To help navigating even this short distance, with VC++, single-click on
params_t and tap <F12>.
 
V

Victor Bazarov

cppaddict said:
I recently started using typedefs and am curious if they are ever
considered evil.

In particular, I'm thinking of a situation where a typedef is used in
a file but defined in another, included file. Someone reading the
code might have to track down the original definition to make sense of
the code, and thus it reduces readability.

I didn't find anything int the C++ FAQ denouncing typedefs, though, so
I'm guessing they're not considered bad form. Anyone have thoughts on
the subject?

Typedefs are as important in C++ as abbreviations in English. They
add about as much confusion, as well. However, the most important
part (I believe) relates to the use of certain aliases in the Standard
Library, and I mostly refer to such typedefs like 'value_type',
'difference_type', 'iterator_category' for iterators, for example.
Without them there would be no clean interface between template functions
in the Library and custom iterators designed by other people. The same
goes for 'value_type' for containers, 'result_type' for functions and
so on.

Victor
 
C

cppaddict

Philip,

Thanks for your reply. I'd like clarification on one point, if
possible...
If another module
somewhere needs a std::map<string, string>, I would _not_ put params_t into
a header that both its modules can see. I would write another typedef in
that module, with a different name.

Or even the same name. I just tried redefining a typedef when the
same one had already been defined, and it compiled without errors.
Doing this would be one way to resolve my initial concern. Or is that
evil? what do you think?

Thanks,
cpp
 
C

cppaddict

Without them there would be no clean interface between template functions
in the Library and custom iterators designed by other people.

Victor,

Thanks for your reply. I'm intrigued by the above statement, but
don't really understand it. Could you elaborate?

Thanks,
cpp
 
V

Victor Bazarov

cppaddict said:
Victor,

Thanks for your reply. I'm intrigued by the above statement, but
don't really understand it. Could you elaborate?

If you write a custom iterator that is supposed to be used in some
kind of library function that expects a, say, forward iterator, and
makes use of what the iterator refers to, then you have to define
a special type in your iterator class that would have the name (or
an alias) 'value_type'. You will of course adhere to other rules
as well, like defining operator++(int) for your iterator class, etc.

You could solve the need to define 'value_type' as a nested type,
or, especially if you have your iterator a template as well, you
might want to have 'value_type' an _alias_ for something else, like

template<typename T> class myiterator {
typedef T value_type;
....
};

Now, if there were no typedefs, the way to define 'value_type' to
be a member of 'myiteratore' would be to actually name the argument
that:

template<typename value_type> class myiterator {
....
};

That's fine for a generic template. What if you need to specialise
your 'myiterator' for, say, "int"?

template<> class myiterator<int> {
....
};

Now, it doesn't have "value_type" member any longer. And there is
no way to introduce "value_type" for 'myiterator<int>' specialisation
without a typedef:

template<> class myiterator<int> {
typedef int value_type;
....
};

Victor
 
V

Victor Bazarov

cppaddict said:
Philip,

Thanks for your reply. I'd like clarification on one point, if
possible...




Or even the same name. I just tried redefining a typedef when the
same one had already been defined, and it compiled without errors.

That I don't think I understand (or even believe).

typedef int INT;
typedef unsigned INT; // will cause error
Doing this would be one way to resolve my initial concern. Or is that
evil? what do you think?

Victor
 
C

cppaddict

typedef int INT;
typedef unsigned INT; // will cause error

I should have been more clear. What I did was:

typedef int INT;
typedef int INT;

Only makes sense, of course, when the statements are in different
files. Would that be evil?

Thanks,
cpp
 
V

Victor Bazarov

cppaddict said:
I should have been more clear. What I did was:

typedef int INT;
typedef int INT;

Only makes sense, of course, when the statements are in different
files. Would that be evil?

Evil, no. If it's allowed by the Standard, how can it be evil?
Redundant, yes. The problem comes when in one file you change
it to something and forget to change in the other. Then somebody
else will never know which one is the intended type (without
looking at the version control system and seeing when the change
was made, or without talking to the person who made the change).

V
 
P

Phlip

cppaddict said:
I should have been more clear. What I did was:

typedef int INT;
typedef int INT;

Only makes sense, of course, when the statements are in different
files. Would that be evil?

Not using include guards would be non-good.

BTW please read /The C++ Programming Language/, and /{Design & Evolution |
Ruminations | Exceptional | Effective | Accelerated} C++/ for extra credit
here...
 
A

Alan Johnson

cppaddict said:
Hi,

I recently started using typedefs and am curious if they are ever
considered evil.

In particular, I'm thinking of a situation where a typedef is used in
a file but defined in another, included file. Someone reading the
code might have to track down the original definition to make sense of
the code, and thus it reduces readability.

I didn't find anything int the C++ FAQ denouncing typedefs, though, so
I'm guessing they're not considered bad form. Anyone have thoughts on
the subject?

Thanks,
cpp

typedef double INT ;

That would be fairly evil.

Alan
 
J

JKop

cppaddict posted:
In particular, I'm thinking of a situation where a typedef is used in
a file but defined in another, included file. Someone reading the
code might have to track down the original definition to make sense of
the code, and thus it reduces readability.


As is exactly the case with:


class Monkey

struct Ape

union Primate

typedef Mammal




-JKop
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top