C did not have a standard for 18 years, it was first created in 1972, and ANSI C didn't appear until the spring of 1990. I'm not suggesting that it took them 18 years to write a spec, it's that it wasn't really needed for a long time. Expecting Rust to have one after five years is aggressive. Some languages have done this! I think we'll end up somewhere between what C did and what C# did, in this regard.
However, you do also bring up something that's a good point when it comes to this discussion: a lot of people treat "a spec" as a binary thing: a language has it, or does not have it. But specs are written by humans, and have their own mistakes, bugs, errata, etc.
One of the reasons that we haven't wanted to declare "this is the spec for Rust" is that we want to have a good, possibly even formally verifiable spec. The reference is basically at a fairly reasonable informal spec level.
[1] https://fzn.fr/readings/c11comp.pdf
[1] well, you can today by swapping malloc for a GC-enabled implementation, but the fact is that almost nobody does.
You don't need GC for this (at least, in the sense of "we'll call free for you"), you just need to verify that things passed to free were handed out via malloc.
Of all the potential issues that might be attributed to C, undefined behavior (UB) is the one that creates few to no problems at all.
To me, complaining about UB is like complaining about the quality of a highway once they intentionally break through the guard rails and start racing through the middle of the woods.
The reason why some behavior is intentionally left undefined is to enable implementations to do whatever they find best in a given platform. This is not a problem, it's a solution to whole classes of problems.
C is not unsafe if you only write safe code. But humans are fallible, and "just don't write unsafe code" is not a solution.
If you want to go with that analogy, UB is a kin of you intentionally pointing your gun to your foot, taking your time to aim it precisely on your foot, and in spite of all the possible warnings and error messages that are shouted at you... You still decide that yes, what you want to do is to shoot yourself in the foot because that is exactly what you want to achieve.
And then complain about the consequences.
Yeaaaah not really:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static char a[128];
static char b[128];
int main(int argc, char *argv[]) {
(void)argc;
strcpy(a + atoi(argv[1]), "owned.");
printf("%s\n", b);
return 0;
}
compiles with no warning using clang (8), even with -WeverythingAnd that’s a super easy case, it’s not a use after a dynamic callback somewhere freed a pointer it did not own, or a function 5 levels deep (or worse in a dll) didn’t check its input pointer which only became occasionally null years later.
> UB is a kin of you intentionally pointing your gun to your foot, taking your time to aim it precisely on your foot, and in spite of all the possible warnings and error messages that are shouted at you…
Because they could hardly be more wrong, the average UB is completely invisible to static analysers because it's a dynamic condition which the type system is not smart enough to move to static. That's why it's an UB and not, say, a compile error.
Now, I think that particular argument is poor. The more defensible version would be to look at the proportion of errors that occurred in C that would not occur in your language of choice, versus the number of errors that occur in this other language that would be unlikely to occur in C. And for completeness it would be good to do some sort of evaluation as to whether they were other gotchas like performance of the resulting code and programmer productivity. I expect that in the grand scheme of things, C is not the best option, but 100% perfection is an absurd goal post and makes it a lot easier for people to dismiss your argument.
I looked through the documentation and cannot find what hardware it runs on and how to set it up. The Getting Started for real hardware returns a 404 page: https://doc.redox-os.org/book/real_hardware.html
It is still in use, because when governments want safety above anything else, they buy such OSes, not UNIX clones.
https://www.unisys.com/offerings/clearpath-forward/clearpath...
The numerous and regular terrifying security bugs that are being found in ancient tools (some 30+ years old) are a living testament that the philosophy you quoted just doesn't translate that well into the reality of humans programming the current breed of computers.
Hence the existence of languages like Rust and the recent general strive towards more correctness and more compile-time catching of potential problems (especially in light of GCC 10's new `-fanalyzer` flag).
But even more than that, I think a lot of people would like to overlook that programming is fundamentally unsafe. Even if you're working in a safe language, that language's runtime is almost certainly in an unsafe language, making syscalls through a library written in an unsafe language, interacting with an OS written in an unsafe language, interacting with hardware running on firmware written in an unsafe language.
Sure there should be a boundary somewhere. But whether that boundary should be a type system or valgrind/cppcheck/etc. differs case-by-case.
y = x;
x += 1;
x -= 1;
true == (x != y);
But I don't know of any actual integer machine that would want integer overflow to actually be UB.Your metaphor brings to mind an image of someone who can see the guard rail, and then deliberately chooses to expend quite non-trivial effort to break them. This is not an accurate metaphor.
As I'm not in the metaphor fix-up business, because I believe they tend to mess us up in precisely this sort of way, let me simply directly point out this gets it backwards. The default is that you will write a program shot through with undefined behavior, and you must make quite substantial, intellectually-challenging efforts above and beyond the intellectual challenge of writing something in C at all that at least sometimes works, to write your program in a way that doesn't have UB in it. It has no resemblance to driving down a road in a normal fashion and then bashing guard rails down.
Sure, if those guardrails are 1mm tall and so barely visible, then that's a valid analogy to C. I hope you can see why this is not an ergonomic design that will lead to safe programs (or safe highways).
Right now I see more efforts coming out Microsoft and static analysis tool vendors than any WG 14 mailing.
Dictating that all architectures implement UB the same way would have significant overhead, since it would force programs that don’t rely on UB to run in emulation on all but one architecture (at best).
Implementation-defined behavior works as you say, where each compiler can define how it responds to certain circumstances.