I know some people have posted along those lines in the past. I
can't say as I agree with that viewpoint, though.
A typedef can be viewed as an abstract type name: once something
has been typedef'd, one can use the type name in user code without
any consideration of what is "underneath the hood".
But so can a "struct". After all, "struct" stands for "STRange
spelling for User-defined abstraCt Type", as you can see from the
uppercased letters in the phrase.
Note that "struct <identifier> {" actually *does* define a new
type (typedef does not -- in the sequence "typedef struct <id> {"
it is the "struct ... {" part that defines the type). This new
type is different from, and incompatible with, all other
differently-named types:
struct time { double val; };
struct temperature { double val; };
struct money { double val; };
gives you three incompatible types, so that you cannot assign a
"temperature" to a "time", for instance.
In addition, structs allow (but do not require) you to make the
type completely opaque, by omitting the "{ <contents> }" part:
struct schedule;
Now "schedule" is an opaque type; none of its members can be
modified. This enforces the abstract-ness: not only *should*
you not inspect the innards, you *can*not.
The one big flaw in this technique occurs in C89, where it is
impossible to create constants that have a structure type. This
is fixed in C99, with its "compound literals".
"struct region" on the other hand requires that one knows something
about what is under the hood -- namely that it is a struct. At
the very least, that tells you some things that the implementation
-cannot- do with it, such as arithmetic operations. That level of
knowledge is none of the business of the user code that just needs
the name of an abstract data type.
One could, I suppose, go ahead and declare that -all- abstract data
types names in a program shall be struct tags, so as to put everything
on an equal footing.
Yes; and I tend to argue for this, except where the convenience of
exposing the hidden mechanisms underlying the type (so that it is
*not* an "abstract" type after all) is sufficiently compelling.
If the user is allowed to "know" that the type is integral,
floating-point, pointer-y, or similar, and make use of that knowledge
(e.g., by incrementing variables of that type), then -- and only
then -- does it really become a candidate for "typedef"ing.
It seems to me, though, that doing so would
merely increase the amount of typing, and would make it more of
a nuisance at the implementation level, since one would have to
put in a tag reference even if the underpinings turned out to be
an arithmetic type. typedef'ing a struct tag into type name
does not have those disadvantages.
If you write, e.g.:
temperature_type x, y, z;
...
z = x + y;
you have demonstrated that "temperatures" are not abstract after
all and can simply be summed (which is not generally true of
temperatures, except if expressed in Kelvin or Rankine or similar).
So I would say, instead, "using a struct tag does not have that
disadvantage".