let foo: int = 0
Instead of int Foo = 0;
This makes me sad let foo: int = 0
Instead of int Foo = 0;
This makes me sadIn C++:
struct MyType {
int field;
};
MyType m;
In C, you would need a typedef to get the same behavior, but the same applies otherwise. typedef struct {
int field;
} MyType;And so it also leads to situations where a human thinks "I made a Doodad" but the compiler sees instead "For some reason the human just decided to draw my attention to the fact Doodads exist, which I already knew". In a language like C or C++ where you do need to constantly repeat yourself because it's designed for 1970s compiler technology, warning about this will lead to too many false positives, so it's not done. C++ lock guards are a famous example where this happens - leading to code where authors and even sometimes reviewers believe a lock has been taken properly, but from the compiler's perspective there was never any lock at all so mutual exclusion isn't achieved.
C++ suffers from requiring arbitrary tokens of lookahead before being able to determine whether something is a declaration or an expression statement, which is a consequence of the combination of C-style declarations, function-like casts, and function-like constructors.
For example, here, the parser cannot know whether the variables x, y, and z are being redeclared in the same scope, or if they're being evaluated and discarded, until it reaches the "new int" part. Last time I tested it, clang++ parsed it correctly, but not g++.
int x, *y, *z;
{
int(x), *y, z, new int;
}
In C++, "int(x)" is equivalent to "(int) x" (and this doesn't exist in C), but as a holdover from C, it also allows redundant parentheses in declarations, so one could also just redeclare x in a new scope like this (in both C and C++): double x;
{
int(x); /* x is an int now */
x = 5;
}
I think this is a variant of the most vexing parse[2], which your lock guard example also sounds like an example of.You probably already know about this, but I was surprised by that example even knowing that C++ requires arbitrary tokens of lookahead to parse correctly, because I had only seen the Timekeeper example from Wikipedia.
There's also the problem that it can't parse something like this unless it knows whether it's supposed to be a template instantiation or an expression statement, but I think that's just an extension of the typename/variable problem that it inherited from C.
a < b, c > d;
[1]: https://en.wikipedia.org/wiki/Lexer_hack