Mars Climate Orbiter was lost because they forgot to convert units between different systems. That's an error that can (and probably would) be done in all type-safe languages I know of.
Sure, unit wrappers are much more like "memory safety checks" in C, in that they are incomplete and can be bypassed. In that sense, the war against raw types is necessarily a cultural one.
It could be prevented if you could express units in the type system. Declare numeric_value_in_meters and numeric_value_in_yards as types and problem solved. Sure, it still possible that someone would not do that, but having this option is statistically better than not having.
It's only your opinion that the code is wrong based on the interpretation of the program's identifiers through an English dictionary. It is well-defined ISO C. Even the termination status is well specified, since the float value will truncate to 0, which is EXIT_SUCCESS.
Any program in any language can be regarded as not having passed checks for some imaginable something.
A perfectly good poker game is semantically wrong because the customer asked for an accounting application. The compiler should have checked the code against a formalized version of the requirement spec, damn it!
>It's only your opinion that the code is wrong based on the interpretation of the program's identifiers through an English dictionary.
No, that isn't quite right. I'm the one who authored that code example so even if I used opaque non-English struct tag names such as "struct s1{}" and "struct s2{}" instead of "struct meter{}" and "struct inch{}", my brain intended for s1 and s2 to not be mixed and matched carelessly. Poster mikulas_florek suggested wrapping plain ints with a struct and my example shows that that workaround doesn't accomplish what he says it does.
>It is well-defined ISO C.
Yes, and I wanted to emphasize that truism by showing a live example of a successful compilation in ideone.com!
I thought the thread was about higher-level semantics rather than the set of trivially true sequences of text input that the compiler accepts.
It's trivial to come up with successful compiles of C code that does invoke undefined behavior.
Successful C compilation rarely means that only higher-level semantics not encoded into type system is now violated.
The battles in C are already being lost in the trenches of lower-level semantics.
If worrying about these higher level things and getting them right were the only problem in C development, C development would be in fantastic shape.
In safe languages which don't have type systems that can express pounds versus inches in inviolable ways, that sort of thing is rarely any sort of obstacle to real work; it's a fluff concern.
If I have to program in something which has no way of enforcing pounds being added to inches, and that is the only significant drawback of that language, I'm laughing.
It's hard to discuss this without using any specific "type-safe" language.
1. you can have the same problem in type-safe language, since it will probably have cast to int too
2. do not use builtin operators in C for that, instead create new functions, e.g. addMeters(Meters a, Meters b);
3. hide the int in *.c file
- do not use builtin operators in C for that,
- instead create new functions, e.g. addMeters()
- hide the int in *.c file
Those are "best practices" instead of compiler-enforced type-check errors. Likewise, suggesting a best practice such as "don't free() memory twice" is not the same as a GC-language (Lisp/Java/C#/Go) freeing memory on the programmer's behalf or a static-ownership checker (Rust) preventing a programmer from making that mistake.
You can write the exact same wrong code in e.g. C#
public class Meters { public int x; }
public class Yards { public int x; }
public class Kilograms { public int x; }
Meters m = ...
Yards y = ...
Kilograms k = ...
k.x = m.x + y.x;
all my sugestions for C are basically the same in C#
- do not use builtin operators in C# for that instead create new functions, e.g. addMeters()
- hide the int in *.c file == make it private in c#
> Yes, you can. But at least you have a better option and better chance of other people using it, so statistically you'll have less errors.
I highly doubt that this specific bug would not happen in any typesafe language. The only way I see this not happening is if there is no native float-like type. Is there such language? They could have make it safe in C, and they did not, probably because it's convenient to use float.
> No, do not add another rule to a million of rules people have to already follow, make compiler worry about enforcing that, not developer.
It can be implemented in C so it's forced by compiler.
Yes, although you should probably do struct value_in_meters { int in_meters; }, so that e.g. x.in_meters / y.in_inches (will compile, but) looks as wrong as it is.
Yes, but nothing will stop you from casting pointer to meters into pointer to yards, while many C features force or encourage this behaviour. You also cannot override operators for combining those units. And the value is still just int.
> casting pointer to meters into pointer to yards, while many C features force or encourage this behaviour.
What C feature forces or encourages casting Meters* to Yards*?
> You also cannot override operators for combining those units.
The lack of operator overloads has nothing to do with typesafety. There are languages which are considered typesafe and which do not have operator overloading.