Fog Creek Software
Discussion Board




typedef is evil, and other truisms

From LinuxJournal, kernel modules style:
===========
typedef Is Evil

typedef should not be used in naming any of your structures. Most main kernel structures have no typedef.

Using a typedef only hides the real type of a variable. There are records of some kernel code using typedefs nested up to four layers deep, preventing the programmer from easily telling what type of variable they are actually using...

Never define a typedef to signify a pointer to a structure, as in the following example:

typedef struct foo {
        int bar;
        int baz;
} foo_t, *pfoo_t;
==========

So true.  What else is evil?

typedef unsigned long DWORD;  Oh the insanity!  A word, prior to MSFT new math, was a machine type, in '286 land 16 bits, in RISC land 32 bits.  Now we have code littered with meaningless DWORD.  Pittiful.

char *lpszMyString; Hungarian crap.  Pathetic!  long pointer to string, zero terminated.  Aren't all ANSI C lib calls based on null terminated strings?  (redundant), long is obsolete, and its not a pointer to string, its a pointer to char.  Just plain wrong an lame.

#define IN
#define OUT

Lame, lamer, lamest:  int func( IN int x, OUT void*y );

x is non mutable to the caller, so IN should leave you scratching your head - huh?  OUT??  Well if it were not to be modified, then use const, otherwise its assumed it will be modified.  Disgusting.

I could go on...  but that felt good...

Nat Ersoz
Thursday, June 27, 2002

hehehe.

James Ladd
Thursday, June 27, 2002

I totally agree with the notion that the typedef for structs is unneccessary and confusing. What is the use anyway. I also back up the point made about DWORD. But I think saying typedefs are evil is a little harsh. When you start using the STL (or other template based classes), you will seen embrace typedefs as very convinient and useful (and not confusing at all, provided you choose good names for your types). Or do you really want to type something like

std::vector<std::list<unsigned int> >::iterator

in your for loops over and over again? And this is a very harmless example.

Also, sometimes you really want to hide the real type your are using, because you might want to change it later without messing up the interface.

So, typedef is not evil in itself, it is just one of the language features that tends to be misused.

Have fun,

Jutta Jordans
Thursday, June 27, 2002

I for one am not going to stop using typedefs because some linux kernel hacker thinks they're evil.

A typedef provides an abstraction which is helpful when you don't need to know the underlying type. In addition, it provides a level of type safety higher than the binary one. Jutta makes good points too.

Some of you may not be old enough to remember that once upon a time in the C programming language, using typedef on a struct declaration was a way to avoid having to use the struct keyword every time you wanted to reference the struct. It's one of those programming habits that just got stuck.

I don't care if you decide to typedef a pointer to a struct or not, but whatever you decide on, including it in the coding standard is a good idea for consistency.

Big B
Thursday, June 27, 2002

I dislike declaring things as evil/wrong/bad/dangerous. Its usually used in a situation where "XXX is very very easy to misuse" and not "XXX is impossible to use correctly".

On the typedef note, the intention is to rename it to be easier to know/write, such as the STL case noted above, or where the programmer does not NEED to know the type, and so it can be changed, such as for time_t and size_t.

Another good example is the const_cast in C++. Easy to misuse, but it CAN be used quite well to maintain const-correctness in C++ code.

There are no absolutes. Well, really few anyway. If we allow things to be declared anathema because of specific instances, we will outlaw everything 8-}

Mike Swieton
Thursday, June 27, 2002

I have an anon quote I like:

"We see the writing on the wall, and all we do is criticize the formation of the letters".

This is one of those kinds of arguments.

Joe AA.
Thursday, June 27, 2002

JoeAA,

Nice quote.  Any idea where its from?

Ged Byrne
Thursday, June 27, 2002

>#define IN
>#define OUT

>int func( IN int x, OUT void*y );

Hey that's cool. I'm gonna start doing that -- aids in the documentation. Thanks Nat.

typedefs? They're great; use 'em all the time on structs. Though I never typedef to hide a pointer, never typedef to rename a simple type and never typedef through multiple levels. Yeah, I agree those are lame. Typedefs greatly improve readibility when using function pointers.

Long live the typedef, rah rah, etc.

X. J. Scott
Thursday, June 27, 2002

I don't know anything about "main kernel structures", but as a scientifc programmer (writing simulations for research), typedefs are great. As was said, they help abstract and simplify program logic.

A simple example is the creation of a Vector structure, to easily allow the manipulation and passing of 3D position values. This is simpler than manually creating and managing ,multiple x, y, z variables, and passing them individually.

As always, use the right tool for the right job.

D. fischer
Thursday, June 27, 2002

typedef is "evil" is certainly extreme - obviously someone is making a statement.  So I shouldn't have called it a "truism", I should have called it a rant. Much better.  Favorite RANTS.

Nevertheless, typedef struct xxx {...} XXX, *PXXX;  -- *PXXX that is pure evil.  DWORD - not pure evil, just disgusting.

IN and OUT, garbage.  Use const, it serves a purpose and its what you mean.  No more, no less - that's always best.

Also, I don't always agree with kernel style points. Some of my favorites:

. prefer C++ // comments over C style /* */
. prefer vertical inline braces over K&R.
. my favorite typedef (from <unistd.h>) typedef unsigned long uint32_t, and those like it.

Nat Ersoz
Thursday, June 27, 2002

I should insert the obligatory VB or Java comment here...but I won't.  Truth is I miss programming in C++.  At least a little.Then Again, I liked Ada.

I think in the typedef for use in the STL, it may almost be better to subclass than to typedef.  I've never tried it, buyt it seems like it would promote code documentation, and be more consistant with the C++ style of things.  I wouldn't typedef other classes, why STL?

adam
Thursday, June 27, 2002

The point of the DWORD is portability.

Yes, it's a lousy name - DWORD is too machine specific. But consider another important Windows typedef:

typedef PVOID HANDLE;

Is this typedef really all this evil? We don't CARE what a handle is - we just want to use it.

With DWORD, the whole point is that MS can change the size of a DWORD as the OS migrates - I believe it DID change going Win32->Win64 for example.

As for the "don't typedef structs" thing - well, a typedef by itself doesn't really offer much except the chance to avoid the struct keyword. It doesn't bother me - I program in C++ anyway.

Chris Tavares
Friday, June 28, 2002

>typedef PVOID HANDLE;

the HANDLE is ok, it is something, that assumes a certain usage (this variable is used as a handle to something).

I hate the PVOID, though. What's the use of that? Why on earth not stick to void*? Surely this is not a compatibility issue. (same for INT, UINT, SHORT etc.) When there is a type that is native fot the language, why not just use it, for god's sake. Otherwise you might head into trouble. I remember using UINT with some library (I do not recall which one) and ending up in a total mess because they had defined it as unsigned short (not very intuitive, eh?) The only sensible meaning for UINT would be an unsigned int. So just use that (take a ten finger typing course or use auto completion if you are too lazy). Even better is Windows type BOOL which is defined as an int in one place (windef.h) und as long in another (wtypes.h). For the current 32bit Windows this ends up as the same thing, but still it sucks. If I have a type called BOOL, bOOl, BoOl or the like, I expect it to be a bool and nothing else. *grmml*, *hmpf*, *hugh*, ranting is fun...lalalal...

Sorry,

Jutta Jordans
Friday, June 28, 2002

HANDLE, fine - although one of Scott Myers'  effective C++ 'isms is to not return pointers to internal data structures.

PVOID:  portability beleive it or not:
#ifndef Win16
typedef far void* PVOID;
#else
typedef far void* PVOID;
#endif

or something inane like that.  Regardless of the rationale, its still lame.

As for Win64, they invented a new one QWORD:  4 16 bit "words" - enver mind that a "word" is now completely obfuscated by this point.

If you want an int, and you are truly agnostic as to its length, then what is wrong with "int"?  If you are not agnostic about its length, then the typedef should include the length in its name:  uint32_t for example.

Nat Ersoz
Friday, June 28, 2002

Ged... I found the quote buried in the middle of the notes section on a schematic of a guitar amplifier.  Most of the notes like this say things like: "All resistors 1/2 watt 5% except as noted".  I think the engineer/draftsman was not having a good day.  I laughed, especially when I noticed that someone had signed off that the schematic was "approved".

Joe AA.
Friday, June 28, 2002

Sometimes I can't believe at how some people can hate something that they just don't understand...

A double-word being two packed words, where each word is two packed bytes, is a convention. You can cry and rant as you like, but Microsoft didn't invent this. Blame who used this terminology first.

typedef'ing structs: I won't even comment on this. And I think that Linux kernel hackers are the least qualified people to teach good programming practices.

typedef'ing pointers to types: the explicit pointer syntax is only used to mean a paramater "passed by reference". So, PCHAR means a C string, while * CHAR means a char-sized buffer that will be filled with a character. Get it?

IN and OUT: IN means the parameter is only read and left untouched, OUT means that the parameter will be written to, *but its original contents will be ignored*, and finally IN OUT means that the parameter will be read from *and* written to. Try to express that with "const". You also forgot the prototype macro OPTIONAL. OPTIONAL means that a zero can be passed for that parameter, and it won't affect the function.

See, it's not that "lame". It's consistent, it makes sense. Especially for a (fairly) language-independent API like Microsoft's.

KJK::Hyperion
Saturday, July 06, 2002

*  Recent Topics

*  Fog Creek Home