3 ms·
The part about potential C++ "successor" candidate languages had this interesting tidbit: > This leads to four approaches: > * We do not break backwards com
by saghm 3y ago
The part about potential C++ "successor" candidate languages had this interesting tidbit:
> This leads to four approaches:
> * We do not break backwards compatibility, and we ignore the memory safety issue (this is the ‘do nothing’ option).
> * We do not break backwards compatibility, but we try to make things as memory safe as possible given the constraints we have.
> * We break backwards compatibility, and we try to make things as memory safe as possible but still remain unsafe.
> * We break backwards compatibility, and we become memory safe by default.
> The first option is seemingly untenable, but is also where I see C heading....
> The second option is how I view at least one of the possible C++ successor languages, Circle.....
> The third option is where the most famous successor languages live: Carbon and cpp2....
> But what about a fourth option? What if someone did a TypeScript for C++, but one that was closer to what Rust does? You might argue that this is basically just Rust? (Interestingly, it is also sort of what Zig is with C: you can use the same compiler to compile a mixed codebase, which is close enough in my opinion.) What makes me worry about option #3 is that it doesn’t pass the seeming test that is coming: memory safe by default. I still think moving to a #3 style solution is better than staying with #1, but is that enough? I don’t know, time will tell.
When put that way, I can't help but wonder about approach #3; if you're already going to break compatibility, why not go the whole way and be memory safe by default? Even as someone who really likes most of the design decisions that Rust has made that are orthogonal to memory safety, and there's a lot of room for differentiation here. Offhand, some of the features of Rust (and its ecosystem) that I've seen people express a desire for alternatives on include:
* package management (centralized repos, lack of namespaces)
* scope of stdlib (relatively batteries-not-included e.g. regex, randomness APIs, http clients, async runtimes all being third-party)
* error handling (lack of exceptions, special operator to early return, somewhat prone to boilerplate like Ok-wrapping without resorting to heavy use of macros)
* integer semantics (no variable width or decimal type in std, overflow checked in debug but allowed in release mode, no implicit casting but lossy explicit casting allowed)
* type definitions (structs/enums with traits, no inheritance, reliance on the "newtype" pattern for certain things)
* function definitions (required type annotations for parameters and return values no overloading, no optional parameters, no variadic arguments)
* syntax/readability (ML-style type annotations, immutable by default, postfix operators like ? and .await, use of macros instead of functions for printing/formatting strings)
* concurrency design (built-in support for locks and 1:1 OS threading, de facto need for third-party runtime to use async, need for 3rd-party libraries for channels other than the deprecated ones in std, no "structured concurrency")
* opinionated APIs for allocations (heap pointers constructed via generic type wrappers, panicking by default if allocation fails, non-trivial boilerplate required to swap out allocator)
* linking (statically linked dependencies that don't use FFI, dynamically link to system's libc by default)
I have to cut myself off here because I keep thinking of more stuff as I write this list, and I probably wouldn't run out of ideas any time soon. I think there's plenty of room for design space for a systems language that's memory safe by default but doesn't look or feel anything like Rust by making different choices on some or all of the above concepts, and that's without even getting into the fact that the unsafety boundary itself can be defined in a variety of different ways, a point that the blog post makes after contrasting the way Java, Go, and Rust expose the ability to do "unsafe" programming:
> If we think about all of these designs, they all are very similar conceptually: safe code is the default, but you can call into some sort of unsafe facility. And everyone is very clear on the relationship between the two: while the unsafe facility exists to be used, it must uphold the rules that the safe world relies on. And that means that safety and unsafety have a super/sub-set relationship. In the core is unsafety. But at some point, we draw a line, and on top of that line, safety exists.