Why use C++ instead of C

Well...consider this:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// OK
{
	typedef struct Y {float a;} Y;
	int Y = 2;
}
// OK
{
	enum RGBColor {Red, Green, Blue}; // user defined type RGBColor
	RGBColor myColor = Red; // a RGBColor
	int RGBColor = 7; // should produce an error
}
// Not OK
{
	enum RGBColor {Red, Green, Blue}; // user defined type RGBColor
	int RGBColor = 7; // should produce an error
	RGBColor myColor = Red; // a RGBColor; error: syntax error : missing ';' before identifier 'myColor'
}


Stroustrup called this a "C compatibility hack."

In C, the struct tag is not a "real" type. A common practice is
1
struct s{/*...*/} s;
The C practice creating a user defined type via typedef solves this.

In C++, the struct tag defines a type and the typedef just adds another type name;
thus the "pollution".

- tim
RomulusTFM
Well...consider this:
1
2
3
4
5
// OK
 // {
	typedef struct Y {float a;} Y;
	int Y = 2;
 // }


Oh wow, man.

I was about to ask if you'd tested this, 'cause I knew I'd previously tested code samples like this with GCC, EDG, and Clang. (And those compiler front ends do issue an error against this example.)

But holy crap MSVC accepts this.

The Microsoft Visual Studio C++ compiler is so broken.

[Spelling the name out to help future searches to find this.]

The Microsoft Visual Studio C++ compiler is so much more unexpectedly broken than I previously already knew it to be. (And I've written a reasonably thorough __if_exists emulator!)

Ok, so, the above code sample is ill-formed C and ill-formed C++. A typedef name does not co-exist with any other "ordinary" identifier with the same spelling. But in Microsoft Visual Studio C++, it does.

*HOWEVER*, if you use the Microsoft Visual Studio C/C++ compiler to compile this as C code, you do get an error:
1
2
3
x.c
x.c(4) : error C2371: 'Y' : redefinition; different basic types
        x.c(3) : see declaration of 'Y'
To collect myself, I had to take a brief walk away from my machine after posting this. I just came back, and again I cannot help cracking up at the measurable, observed, abject, and possibly bottomless brokenness of the Microsoft Visual Studio C++ compiler.

I'm going for another walk.
Stuff like this is why, even though I've been in J16/PL22.16 since 2004, I can't blame Casey when he flies off the handle about the committee (not even when the rant becomes unnecessarily hurtful).

If the committee *really* cared, collectively, about portability (which is supposed to be a major reason for having an International Standard that specifies the core language), we would have had a registered, trademarked name for the language whose use in a compiler requires a license that would be granted only after the implementation passes a thorough test suite (so that, for example, Microsoft could ship a compiler, but they wouldn't ship something that called itself a "C++ compiler", because that would have required proof).

Some committee members probably could have found the money for that, but in retrospect, I suspect there weren't any people with access to the means who ever cared enough to make it count.
What do other compilers do with this?
1
2
3
4
5
// Compiled as C code
struct Y 
{
	float a;
} Y;			// is Y a type or variable name?

AFAIK, a C compiler should accept this.

If that's legal then so is this:
1
2
3
4
5
struct Y 
{
	float a;
};
int Y = 2;


To me, this is the root problem.

- tim
For C compiler "Y" is variable, "struct Y" is type.
So first and second examples are legal for C compiler.

clang provides nice "-ast-dump" argument that will show this.
1
2
3
4
5
6
7
8
clang.exe -cc1 -ast-dump a.c
TranslationUnitDecl 0x2ffb0d0 <<invalid sloc>> <invalid sloc>
|-TypedefDecl 0x2ffb5e0 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
|-TypedefDecl 0x2ffb650 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
|-TypedefDecl 0x2ffb6e0 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list 'char *'
|-RecordDecl 0x2ffb730 <a.c:1:1, line:4:1> line:1:8 struct Y definition
| `-FieldDecl 0x2ffb800 <line:3:2, col:8> col:8 a 'float'
`-VarDecl 0x2ffb8b0 <line:1:1, line:4:3> col:3 Y 'struct Y':'struct Y'


RecordDecl is type definition (struct Y). VarDecl is variable definition "Y" is name, "struct Y" is type.

It's funny when you will ask clang to generate C code back from ast:
1
2
3
4
5
clang.exe -cc1 -ast-print a.c
struct Y {
    float a;
};
struct Y Y;

It generates type definition and variable definition separately. That still a valid code.

Edited by Mārtiņš Možeiko on
Ok, the MSVC compiler is in agreement with Clang (or visa-versa).
This is what I thought.

I wouldn't fault Clang for being explicit on the code generation since it's accurate.

This why I think a C++ compiler is going to have to do some strange business with other constructs.

- tim
RomulusTFM
What do other compilers do with this?
1
2
3
4
5
// Compiled as C code
struct Y 
{
	float a;
} Y;			// is Y a type or variable name?

AFAIK, a C compiler should accept this.

Yep.
If that's legal then so is this:
1
2
3
4
5
struct Y 
{
	float a;
};
int Y = 2;


To me, this is the root problem.
Granted, it's silly, but back in the 80's (and the '90s and the naughties and even in the present day) everyone thought they wanted their pre-existing C code to continue to compile
  • without any changes
  • without any new errors from the compiler, and
  • with the same old semantics as in the early '70s
... which meant users were asking for their compilers to inherit as much pre-existing silliness in C as possible (whether they understood that or not).

This is why not-re-inventing-the-wheel probably impedes language development more than anything else.

(Actually, "impedes" is being kind. More like, "brings to a grinding halt".)
Companies are notoriously hard to convince to use language X when they have a 10 year dependency on libraries and software for language A.

I don't want to reinvent the wheel unless...no, I just don't want to.
But code should be maintained or it "rusts."
And backward compatibility has a limit.

So says the man that is running on Vista 'cuz it woks fine for me. :)
Oops; I should have put quotes around "re-".
CppCon 2014: Herb Sutter "Back to the Basics! Essentials of Modern C++ Style"
https://www.youtube.com/watch?v=xnqTKD8uD64

:silly: