25
$\begingroup$

In C, if you declare a struct like:

struct point {
    int x, y;
};

you also have to use struct when referring to point, e.g.:

struct point p;  // declare p as struct point

because all struct, union, and enum names are in a distinct "tags" namespace. Yes, I know you can use a typedef to import a struct's tag name into the current scope:

typedef struct point point;
point p;         // don't need "struct" now

Clearly, a tags namespace isn't needed since C++ effectively auto-typedefs struct (and class) declarations.

My question is: does anybody know what Ritchie's rationale for using a separate tags namespace was? Why weren't struct names just put directly into the current scope so a typedef would be unnecessary?

His The Development of the C Language mentions structures, but nothing about the tags namespace.

Note that I’m really looking for a definitive answer, not speculation.

The only minor benefit is that you can have a struct and variable with the same name, e.g.:

struct stat stat;

To me, however, that's outweighed by ordinarily having to use struct all over the place if you don't use typedef.

For self-referential structures, you don't need the struct prefix either since in C++ you could do:

struct link;     // forward declare link
struct link {
    void *data;
    link *next;
};

That works just fine.


Note that I'm not asking about why a lot of Unix struct members have prefixes, e.g., sin_family, sin_port, sin_addr. Aside from already knowing the answer to that question, it's unrelated since that's about struct members whereas I'm currently asking about struct names in the tags namespace.

FYI: I've been programming in C on-and-off since the 1980s, so I know C. But I've never seen any explanation of Ritchie's rationale for the tags namespace.


I originally asked this question here at Retrocomputing, but it was suggested by Raffzahn and agreed to by Adam Hyland that I ask this question here on Langdev.

$\endgroup$
15
  • 8
    $\begingroup$ I don't know the answer to your question -- which I have idly wondered myself before. But I like your idea that it might be a solution to what in the C# spec we called the "Color Color" problem: you have a type named Color and you naturally want a property also named Color of that type. The C# name ambiguity rules were carefully designed to allow that; maybe there's some reason why in K&R C that was tricky? $\endgroup$ Commented Oct 13 at 7:06
  • 1
    $\begingroup$ You don't even need to forward-declare link in C++ to be able to use it self-referentially. $\endgroup$
    – G. Sliepen
    Commented Oct 13 at 9:40
  • 4
    $\begingroup$ @EricLippert, also known as the "type-token distinction" in wider discourse: en.m.wikipedia.org/wiki/Type%E2%80%93token_distinction $\endgroup$
    – Steve
    Commented Oct 13 at 15:10
  • 1
    $\begingroup$ @PaulJ.Lucas: Constructs in Pascal that use an already-declared type name precede it by a colon or the keyword of, followed by zero or more carets, and nothing other than a type name could appear in the places a type name could appear. $\endgroup$
    – supercat
    Commented Oct 14 at 19:28
  • 1
    $\begingroup$ @JohnBollinger: The existence of the 1974 C Reference Manual that documents an earlier version of the language requiring that the stem of all types start with a reserved word should be recognized as supplying a clear answer to the question. $\endgroup$
    – supercat
    Commented Oct 15 at 19:46

2 Answers 2

19
$\begingroup$

The reason one might use tags is the same as why one would use $sigils. It makes parsing a whole lot easier if you can differentiate the identifiers during the parsing step rather than need semantic knowledge to do so.

Typedefs feel like a later addition to the language. Which then caused issues regarding parsing because now a type isn't always marked by a keyword and an identifier might now be a variable or a type.

The only symbols that need to be exported from the compiled translation unit being sent to the linking step are global variables and functions (which could be considered special kind of global).

Putting everything else into a tagged namespace prevents pollution of that inter-translation unit namespace with type names.

$\endgroup$
11
  • 4
    $\begingroup$ Do you have any evidence that typedef came later? $\endgroup$ Commented Oct 13 at 12:28
  • 17
    $\begingroup$ @PaulJ.Lucas the C compiler in V6 Unix doesn’t support typedef, whereas the V7 compiler does. So typedef was introduced sometime between 1975 and 1979 (or 1978 when the first K&R C book was published). $\endgroup$ Commented Oct 13 at 15:41
  • 2
    $\begingroup$ @StephenKitt I just found this that documents C for 6th Ed. Unix — no typedef. $\endgroup$ Commented Oct 13 at 22:29
  • 2
    $\begingroup$ @PaulJ.Lucas what git logs exist for really old changes? C is a lot older than git. $\endgroup$ Commented Oct 14 at 16:44
  • 2
    $\begingroup$ @PaulJ.Lucas I think what Mark wants to know is, when you said "I tried poking around in the git logs", which logs were you looking in and where can they be found? $\endgroup$
    – kaya3
    Commented Oct 15 at 0:15
2
$\begingroup$

Why weren't struct names just put directly into the current scope so a typedef would be unnecessary?

typedef is unnecessary. There's nothing that you can express in C with the help of typedef that you cannot also express without. It does make a few things clearer, but it can also be, and too often is, (mis)used to make things more obscure.

I acknowledge that

Note that I’m really looking for a definitive answer, not speculation.

, but I don't think there's a definitive answer available at this point.

Dennis Ritchie has acknowledged Algol 68 as having a significant impact on his design of C's type system, so we know that it was well known to him. He may even have drawn C's struct and union keywords directly from Algol, which uses the same ones to declare its structure and union types. Algol 68 has an analog of C's typedef (modes), but no analog of C's tags. Neither did C's direct ancestors, BCPL and B, have any such feature (they had only a very simple type system, whose shortcomings were the initial inspiration for C), so this seems to have been Ritchie's own invention.

Why introduce tags and the tag namespace when Ritchie's main model for C's type system did things differently? I see only a few alternatives, none exclusive:

  • tags and keywords may have been a convenience, making the compiler easier to write or easier to keep small (remember that executable size was a major consideration in that day).

    • as a special case of this, tags, and especially type-category keywords, might have simplified the initial introduction of structures into the early C language parser.
  • Ritchie may have considered tags and pervasive use of the struct keyword to be a superior design. It does have the advantage of being clear at the point of a declaration what type category each declared object belongs to, which I personally value today. I prefer to refer to structure, union, and enum types in my C code using keyword / tag syntax.

I'd be inclined to lean in the pragmatism direction.

$\endgroup$
1
  • 1
    $\begingroup$ When I said "... so a typedef would be unnecessary," I meant, "... so a typedef would be unnecessary for making using structure types not require the use of the struct prefix." $\endgroup$ Commented Oct 14 at 23:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .