3 ms·
Xr0 makes a "limited subset of C89" as safe as Rust, after adding cumbersome function annotations to every function and limiting the types of allocation pattern
by nneonneo 3y ago
Xr0 makes a "limited subset of C89" as safe as Rust, after adding cumbersome function annotations to every function and limiting the types of allocation patterns that can be used. (Also: "Buffer overflows/underflows" prevention is not implemented yet. So the Xr0 programs are not yet safer than Rust.)
- josephg 3y ago> Also: "Buffer overflows/underflows" prevention is not implemented yet. Rust also statically prevents race conditions in multi-threaded code, via the Send and Sync traits. This blog post describes annotations which make Xr0 a safer dialect of C, but its still far less safe than rust. This looks like a cool project, but I've gotta agree with other commenters. The blog post title is a false promise. If you think the project is good (and it looks good!), then why lie about its capabilities?
- Animats 3y agoRight. It's yet another "C with annotations". Been there, done that, as have many others. The fundamental problem with fixing C/C++ is that you have to take stuff out of the language to make it safer. That's not going to happen. The trouble with going to Rust is that the language is so different from C/C++ that conversion is tough, both for code and for programmers. It's not the syntax. It's the semantics of affine types. Strict single ownership requires a major rethink of program organization. The result is, arguably, better programs. But it's a wrenching change. Interlinked data types have to be completely redesigned. (There are people trying to fix that problem in Rust. There's "Arc::new_cyclic", which lets you have weak backlinks. Now you can find your parent in the hierarchy, which means you can do object-like things if you want to. There's also UniqueRc in development.[1] There's the theoretical possibility of proving at compile time that no .upgrade() operation on such objects will result in a failure due to two strong pointers existing at the same time. If that could be done, the reference counts could be eliminated and Rust would have safe back-references. Nobody has figured out how to do that yet. So for now, the mismatch between C/C++ and Rust is pretty bad.) [1] https://github.com/rust-lang/libs-team/issues/90 https://github.com/rust-lang/libs-team/issues/90
- akiarie 3y agoThe only limitation to the allocation patterns Xr0 imposes is that there can be no leaks. Everything else is possible. Yes, Xr0 is young. It took Rust nine years to reach v1.0.0. Xr0 may need slightly over the nine months its had.
- nneonneo 3y agoSo, please don't make (or invite) comparisons to Rust if you know you aren't there yet. Not everyone will agree that you are just making such a comparison "tongue-in-cheek". "Safer than Rust" is an extremely high bar to clear, and you haven't done so, so why title your blog post that way? I am curious to know how you would handle tagged unions, say, something like this: struct object { int type; /* OBJ_INT, OBJ_STR, etc. */ union { int i; char *s; /* heap allocated */ /* etc */ } val; }; Does Xr0 prevent type confusion, and can it model the data-dependent behaviour of any functions that operate on struct object? How would you model things like reference counting? In CPython, for example, one of the most pernicious programming problems is invalid reference counting because the C API functions are rather inconsistent in their handling of reference counts. One has to carefully peruse the documentation to understand if the function will steal a reference (from a parameter), borrow a reference (for the return value), or if it makes a new reference. Such setups are perfect candidates for annotation.
- akiarie 3y agoCan you give an example of the kind of data-dependent behaviour you have in mind? We haven't implemented unions yet, but I see no reason why the approach we describe in the article cannot propagate the tagging info in such a struct. As we explain in the article, Xr0's focus on formalising interfaces allows the verification of each function to be carried out independently. Thus we do reference counting only within individual functions. I'm not sure I fully understand the CPython example. What I can say is that the annotations allow us to capture the semantics such as whether a function destroys a value, stores its value in a global or returned value, or has no net effect on the state of its caller.