It's time to halt starting any new projects in C/C++
twitter.com
twitter.com
https://en.wikipedia.org/wiki/Sony_BMG_copy_protection_rootk...
He extensively reverse engineered and documented "Windows Internals" details before joining Microsoft (and before being "encouraged" to change the name of his business to Sysinternals).
His writings and talks on "The case of..." are master classes on reverse engineering.
https://techcommunity.microsoft.com/t5/windows-blog-archive/...
I'm paying attention to him.
Personally, I enjoyed them a lot and I am actually a bit bummed that he stopped publishing new ones...
Granted, I probably would not have read them had I not recognised his name on the cover (there is too much cookie-cutter stuff out there). But I did not regret buying them and I remember being impressed by the fact that this guy wrote Syinternals AND engaging fiction...
My impression from the first book was that the author has a very back and white view of the world. That could very well also affect his day job
https://www.youtube.com/watch?v=mvaUwagX_uU
For a light-hearted take.
Does he still develop the sysinternals tools? Does he program any more or has he settled into the life of an xTO? Rust, C++, what is he using? Did he port all his tools to Rust?
Given that his reputation is in other areas I don’t immediately see what makes his proclamation noteworthy. As someone that read his book and used his tools I’m more puzzled by his statement than motivated to spring into action :-)
Satya Narayana and company out of Azure are a tribe of forward thinkers who rescued MSFT in the long-term by adapting and embracing without as much extinguishing.
PS: Unnamed yours truly is now around the corner from where Winternals was. Small world.
C++ changed a lot over time, and the way modern code is supposed to be written is very distinct from "C with classes", but you still can do that if you want.
https://gist.github.com/caiorss/c7db87df674326793431a14006aa...
It looks pretty much nothing like a C program doing the same job.
A lot of those features were made to make C++ a safer language to use. Eg, with a construction like:
for(const auto& it : ast){
You can't accidentally walk past the end of the array by going one item too far. But C++ still allows you to write code the way you'd do it in C. void foo() { .. }
And others auto foo() -> void { .. }The second syntax was introduced for lambdas and decltype() usage for return types that depend on the parameters (due to look up rules), and some C++ subcultures now use it everywhere.
> auto main() -> int {
Absolutely no reason to masquerade main() in such a fashion!
It's a rule of least surprise, be it for user or fellow developer.
with constexpr etc, and std::move, and unique_ptr in use, many memory safety issues can be contained.
adding cppfront on top can make modern c++ even more memory safe.
Does it really need to include <string.h>?
You can forget the virtual destructor. Maybe the language is excused because it’s only a leak.
You could mess up the what() functions. (It’s not locally obvious that it’s correct in this code.) std::exception is fundamentally dangerous. Rust can get away with safely returning references like that because the lifetime is part of the function’s signature. C++, even modern C++, can’t.
Even the iterative example is only a bit safe. You can’t walk off the end by going one too far, but you can certainly mess up by invalidating the iterator in the loop body.
AFAIK, that's with a caveat of "unless you modified the array length within the loop" (looking at the gist, "ast" is a deque, so you can pop items from either end); IIRC, that C++ construct evaluates the begin and end only once at the start, instead of every iteration (unlike what you might do with "classic" C++ evaluating "it != ast.end()" every time), so it wouldn't notice the change. This is particularly annoying since C++ developers can be tempted to optimize a classic "for (auto it = ast.begin(); it != ast.end(); ++it)" loop into either the new-style "for (auto it : ast)" or the old-style optimized "auto end = ast.end(); for (auto it = ast.begin(); it != end; ++it)" loop, even though that would break the code if "ast.end()" ever changes within the loop.
(Since the initial discussion is actually about C and C++ versus Rust: in Rust, you wouldn't be able to modify the array within the loop, since the iterator is borrowing it, so this issue would be caught by the compiler.)
Checks linked resources
while(!ss.eof()){
ss >> token;
Can cause an endless loop (with finite input stream; for example in case of a read error). p >> x;
if(!p.fail() && p.eof()){
This way of error checking is correct for C++ but not nice (it or part of it can be forgotten with no warning--see below for an instance of it :P). struct stack_empty_error: public std::exception{
const char\* what() const throw(){
Missing "override" annotation here. Can easily fuck it up since overloads are allowed. return " ==> Error: stack empty." ;
}
};
auto x = _stack.back();
_stack.pop_back();
return x;
Correct in C++ but incredibly weird--typical for lowlevel languages that are far away from the user.Also, when I press Ctrl-D, I get an endless loop printing "EXPR+> stack". Typical C++ program...
Bold claim.
Thing is in this case their advice regards the rifle.
It is nonsensical to say “the general can’t hit a moving target with the old rifle, so he should say nothing at all about weapons”. Which is what the person I replied to said.
> With all due respect, this is coming from a Win32 API C programmer who happens to save the code in files with .cpp extension. In other words, not familiar with modern C++.
Edit: Ah, you said "know enough about modern C++", so yes, I agree and was arguing in the wrong bit of the thread.
Nothing you’ve said contradicts what I said.
I think they might have been going for the ludicrous image of sticking a bayonette onto the front of a fixed gun emplacement.
And then other critics saying "Russinovich hasn't demonstrated skill with a machine gun so how can he say bayonettes are obsolete?"
No, but he does need to "know enough about modern C++ to make the statement that we’re discussing".
I could throw a bunch of examples further. For instance how the changes made to rifles because of what Generals thought their engagement ranges would be hampered the western forces who had to fight in Afghanistan.
You should also be skeptical of a General who suggests we go all in on Drone Warfare and not worry about rifles at all.
TLDR, person in a strategic role is rarely the best to assess tactical tools, and will often attribute strategic failures on their tactical tools.
They usually have not been in the trenches for a good while at least (could even be like 20+ years since they've done any development), and they take the ultimate decisions for their whole company for all kinds of languages and environments they have had no experience with... (like a CTO that used to do C back 20 years ago, now having a say in the use of Rust or Node).
Many experts disagree with the way modern C++ evolves.
To say that modern code is supposed to use all the C++11-forward features or else it's obsolete is a massive bias on your part.
All that said, some parts of moder c++ like move semantics do really cut down on defects. People who go out of their way to use *all* of the new toys create codebases that make my teeth itch.
It meant not using stuff like templates, operator overloading, RTTI, exceptions, STL.
The sentence is indeed from a meme template[1], but I thought that my comment would stand on its own.
Note that you might choose to forbid anything that doesn't count as "modern C++", e.g. by enforced linting. Equivalently, you could instead have your compiler reject such programs (perhaps deciding to rip out various features and modules from the compiler, to avoid them being used). Either way, you're no longer writing C++: you're writing some other language (say, "C+++"), which is a sub-set of C++. In which case, you've done what the author suggested: deprecating C/C++ in favour of something safer!
So, you would mandate using Rust without "unsafe", then? Good luck with that.
I bring that up to highlight the weight of his opinion: Russinovich is legendary in terms of his systems programming contributions.
also the excellent book "windows internals", which is kind of like the bsd red book, or the magic garden svr4 book, but for systems derived from the windows nt kernel.
but perhaps his best work is this: https://learn.microsoft.com/en-us/sysinternals/downloads/blu...
a screensaver that produces a realistic blue screen (kernel panic) for the version of the operating system and kernel that are installed, along with a simulated reboot that lands back into bsod as an infinite bootloop. extra bonus points because it also creates fake disk activity (for the era of hdd lights and hdds that made noise) for extra realism during the simulated boot.
I did wonder how a screensaver can crash the kernel, until I remembered what it's supposed to do.
I was embarrassed for quite a while after that.
Most importantly, there's also a complete lack of understanding of the underlying motivations behind both Islamic terror organizations, and cyber crime groups.
I love a ton of things that Mark has built, and I'm glad he's out living his best life. According to the Amazon reviews, a ton of people loved the book, but from my perspective Zero Day is a rare miss.
I used this one at work for some time. Until I came back from my lunch break and got told by my office mate that he helpfully rebooted my PC because it had crashed in my absence.
> Note: before you can run Bluescreen on Windows 95 or 98, you must copy \winnt\system32\ntoskrnl.exe from a Windows 2000 system to your \Windows directory
There be dragons
The way they expose OS internals in a powerful-but-user-friendly way is delightful and empowering. I still remember the first time I used procmon; it felt like a veil was removed from my eyes, suddenly I could trivially see everything processes were doing!
Sysinternals represents an idealized Windows to me: an OS for power users with a GUI-first culture that differentiates it from Unix. Windows itself might not live up to that dream anymore, but at least we have Sysinternals.
Where does it end? If he says mint chocolate chip is the worst ice cream flavor, am I obliged to agree with him because he made sysinternals?
He’s an expert in the subject at hand, and that fact is more relevant than the fact that he’s the Azure CTO. What more do you want?
(And yes, of course you can disagree with him. That has never been doubted.)
It means he has a very informed opinion. That doesn't mean we are forced to agree (I do not), but that we must answer with another informed opinion ourselves.
MR is clearly expressing an opinion and reasons for it and it is up to you to decide whether his experience qualifies him to make such bold claims, whether there are edge cases for exceptions and whether or not you agree or care.
Otherwise, the argument is 100% valid.
When I see Mark's name, I stop and read the article.
The borrow checker worked fine when all I needed to do was pass data up and down the callstack, but anything beyond that was difficult or impossible to express. Has the borrow checker become smarter since then? At the time I was very put off.
Using integer handles as pointer replacements does have some universal benefits though outside of Rust. You can make them more compact, they serialize more easily, etc.
What ? Box, Arc (and weak) are exactly made for this.
No, this is genuinely a big hole in the expressive space of the language. Not a lot of apps really need to do a ton of manual pointer work implementing non-trivial data structures, but some do, and it kinda sucks in Rust.
I've implemented several of such data structures, there is not that many tradeoffs available : safe and easy, or unsafe and fast.
The unsafe parts are still much better than raw C. I don't agree that the language and ecosystem is missing a "big piece". Everything is already there.
Doing this in Rust is still going to be orders of magnitude faster than many other languages. Maybe not C/C++, but then again if you’re chasing pointers in a list maybe squeezing every ounce of performance you can isn’t the #1 priority for the given application. The industry consensus is shifting to the idea that being #1 in security at the expense of being #2 or #3 in performance is a fine trade off.
Is it? That's where Java was 20 years ago.
That being said, you still can't do "naive" cyclical data structures without some additional assistance. But the ecosystem has matured around that: crates like ouroboros[1] provide safe interfaces for creating self-referential structures and datatypes.
Edit: NLL was indeed added in the 2018 Edition[2].
[1]: https://docs.rs/ouroboros/latest/ouroboros/
[2]: https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-201...
That's... not really that fatal. There's a lot of very useful code that can be written using only runtime-provided[1] containers and straightforward ownership trees.
But obviously the big problem is that for applications that do need to do non-trivial reference semantics, Rust doesn't really offer much. Applications with nonstandard allocator paradigms or weak-referenced caches or that need to do complicated graph management are mostly on their own in the world of unsafe.
And the somewhat more cynical point is: for applications that can easily fit within standard containers and standard allocation paradigms, C++ actually works really well already. Use your smart pointers. Use your containers. Follow the rules everyone tells you about not using bare new/malloc. And... it's basically just as safe, because anything beyond that would be unsafe in Rust too.
I don't dislike Rust, really. But the space between "Need to stay away from C++" and "Should probably just have written it in Go" seems to be getting smaller and not larger.
[1] Which in Rust, means "written using a ton of unsafe blocks".
This reminds me of those static provers which prove everything correct up until user input, you know, the place where an attacker will inject their payload.
No because in practice you only need unsafe a tiny minority of the time, whereas C++ is always unsafe.
Most programmers do not spend most of their time writing low-level cyclic data structure libraries. If they did, then indeed some of Rust’s advantages would be mitigated.
If you're perfectly attentive and constantly vigilant, maybe. In practice everyone thinks they're following the rules and everyone messes it up.
That used to be the case 10 or 15 years ago. Today it is much easier to "follow the rules", because:
1. You used to need to tread carefully to both follow them and do what you needed to; now you can do more complex things more easily. Example: In the past, you couldn't avoid new and free being strewn around your code. These days, you can avoid them entirely when not implementing a complex data structure of your own.
2. A decent version of "the rules" is basically explicit: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines
3. The standard library and other FOSS libraries do a lot of the rule-following for you
(4. Compilers are more attentive and do more static checking.)
https://github.com/rust-lang/rust/blob/master/library/alloc/...
It's part of standard lib. And you don't get more idiomatic than that.
Depends what you mean by that. It has 2 pointer to other nodes and element on the heap (EDIT: Not stack). It's bog standard double linked list.
If you're looking for intrusive lists those a very niche data structure.
https://docs.rs/intrusive-collections/latest/intrusive_colle...
https://github.com/rust-lang/rust/blob/master/library/alloc/...
We also have D which can use C/C++ libraries seamlessly.
For those applications you can almost always encapsulate the unsafe code in a data structure library with a safe interface, such that the library is a tiny fraction of the application code. And in many cases someone else already wrote that library. For graphs, for example, there is petgraph.
> for applications that can easily fit within standard containers and standard allocation paradigms, C++ actually works really well already
Not at all. For example it is still easy to corrupt memory using C++ references. Just the other day I discovered a nasty little bug involving absl::hash_map: someone had written "map[i] = map[j]" which is unsafe if the element at i does not already exist --- it can trigger a rehash, invalidating the reference obtained by map[j].
This is something I never understood. Given that a Rust application is running on top of an OS making OS calls... or uses a huge library like FFMPEG... The only safe portion is like the 1% of code being executed.
"such that the library is a tiny fraction of the application code"
I mean, your Rust app uses sockets to pull a video and save it with FFMPEG. The quantity of code executed to do that is like 99% unsafe and 1% safe. Right?
What are we talking about here? I can still find a bug in FFMPEG and ROP-exploit some code in the safe 1%, right?
The same languages and code Rust evangelists (and Mark Russinovich if not one) are blaming is the only code that makes Rust do something meaninful. Don't you agree?
Also, "if it can't be 100% safe right now all at once, then why even bother?" isn't very pragmatic.
It might not be using FFMPEG, but gdi32.dll, winsock2.dll, libc, etc. Correct?
Unless you run on 100% bare-metal, the "safe" code is still a tiny fraction.
What if my linked C library returns an invalid pointer? Rust will still make the assumption it might be valid and play along.
(that might be the reason why Rust likes to compile libraries/dependencies from source)
> Also, "if it can't be 100% safe right now all at once, then why even bother?" isn't very pragmatic.
Never said that. I only say that people thinks "unsafe" is just for a "tiny wrapper around a library" or as parent said "that the library is a tiny fraction of the application code."
At the end, it's not. If you consider the rest of the code that makes a Rust program run, then "library is a tiny fraction" is, in fact, the other 99% of your executing code, and that this code is unsafe (unless you run on 100% bare-metal).
The 1% of code that is your own will, upon creation, have been run precisely zero times, so there is no probabilistic argument to be made for its correctness. Safe languages let you exclude entire categories of mistakes even when your code hasn't been run yet, which seems obviously valuable.
This was referring to using unsafe data structures in Rust by pulling in a Rust library so that your application code doesn't need any unsafe blocks itself. This is a huge win for your application code, even if there's other code that is still "unsafe".
Nevertheless, the more code we write in Rust, the safer we will be. Especially because popular kernels and system libraries are often very well tested these days, whereas application code newly written by developers of varying skill levels likely won't be.
This is "don't write bugs, lol, and you're safe" argument. It has been demonstrated many, many times on HN, that you can cause UB in C++ using just high-level standard containers and smart pointers, without doing anything suspicious with raw pointers. Bugs of that kind are virtually impossible to detect during a typical code-review. So it is not "just as safe". It is tad safer than C, but nowhere near Rust.
> But the space between "Need to stay away from C++" and "Should probably just have written it in Go" seems to be getting smaller and not larger.
That might sound as a rant, but IMHO the designers of Go sadly made some odd choices in areas unrelated to memory management, which put me off from Go. Go is not just Rust with borrow checker replaced by tracing GC. It is a completely different language, with a much different "feel":
* some syntax choices that seem to have no justification other than "we wanted to make it look different than other languages" (ok, one can get used to it)
* no sum types / unions / enums
* code generation / copy pasting instead of proper macros
* error handling not really better than in C (caused by no sum types)
* visibility controlled by character case (so when you want to unprivate sth, you have to find-replace all occurrences; I guess this stupid idea originates from Python)
* unused stuff is hard error (terrible for prototyping)
* you don't need generics, but we've just added them anyways ;d
* no tools for controlling mutability/immutability/sharing (which is still useful in GCed languages)
* data races possible, accidental mutable sharing possible
* no RAII for deterministic destruction of non-memory resources (`defer` doesn't even come close)
* package/dependency management IMHO subpar compared to cargo
When trying to learn Go, I had exactly same feeling as when I first learned Java (after C++) - that the authors of the language designed it for people less capable than the creators themselves. So I didn't like it.
The language causes you to rethink datastructures that were largely created in a single-core context. You can think up equivalent functionality that satisfies the Rust borrow checker but then also lets you trivially parallelize via something like Rayon.
Rc or Arc work for a double LL if you insist on pointers, or a wrapped owned vector with integer based references if you don’t want the overhead of reference counting. But to say “Rust doesn’t offer X” is just not true; you can build anything but it just takes more work and thought, and it is always worth it given the performance and bug classes automatically eliminated by that extra effort. And with unsafe code, you get bare metal access without the rules.
You can still happily have UAF through references. The adoption of string_view has made this super clear. Arithmetic is still very error prone, with confusing promotion rules and little protection for overflows. Pointer arithmetic is still common - yes even if are using typical containers. What do you think is happening underneath the hood when you increment an iterator? Oh, and iterator invalidation remains a fun way of ending up with unsafe code even if everything looks totally fine.
“Welp, can’t write a doubly-linked list in safe Rust so I might as well use C” is throwing the baby, the bathtub, and the rest of the greater metro area out with the bathwater.
Zig aspires to be that minimal language. It seems to have a lot of really good ideas. It’s too bad the compiler is so opinionated that a lot of developers will be alienated by it.
This is a meaningless distinction. No language in the history of languages has ever strictly "replaced" another. Over time Rust will eat into the market share of every language to differing amounts. C and C++ top the list of languages that Rust will likely eat into the most, but of course they will still continue to exist and people will find reasons to continue using them.
> But for the use cases where even C++ is too much, there is no replacement for C.
Rust is a significantly less complicated language than C++. But what does this even mean, anyway? Whose use-case is "A systems programming language, but the spec can only be so many pages long?"
> (and even that’s debatable, given the cyclic references issue discussed here)
struct Node<T> {
data: T,
left: *mut Node<T>,
right: *mut Node<T>,
parent: *mut Node<T>,
}
Wow, so difficult! If the comparison is C, I don't even have to bother writing a safe abstraction around this.I would have used inheritance to create a "ListBaseType" with a "ListElementType" specialization (with all the data required to wrap some element) and an empty "ListNullType" to use as begin/end elements. A quick Google search results in a implementation using "None" instead: https://gist.github.com/matey-jack/3e19b6370c6f7036a9119b79a... (I don't vouch for it!)
In the end the correctness boils down to correctly handling the beginning/end. It does matter little if that's a NULL, None, nullptr or ListNullType.
The real difficulty would be adding thread safety with minimal performance loss.
In a GC language, the runtime has ownership over memory allocations. The "owner" is actually outside the application code, so the application code can have as many reference loops as it likes, as none of them are owning references.
1. Pointers work fine, you're not solving any problems here. 2. You can't rebind references in C++, so you wouldn't be able to delete nodes 3. Even with this insane approach, why would you use inheritance over a sum type? 4. Extra allocations or statics are needed to hold sentinels.
As for why this wouldn't work in Rust, in addition to its many general problems, the fundamental issue is aliasing. Rust mandates that if a mutable reference to an object is alive, then nothing else references it. Thus, it would only work if your entire list was immutable; this may fit within your definition of a sane API, but it's not what most people would want if they were choosing to use Rust.
1. Dereferencing raw pointer is unsafe; but maybe not necessary? 2. `int main (void) { int a = 1; int b = 0; int &ref = a; ref = b; return b; }` 3. union access is unsafe 4. the cost of not having nullptr or similar
Obviously a linked list is trival to implement with pointers; but at least in C++ a naive linked list implementation can easily produce lots of suffering (read: UAF or DF) with a `delete list.getPointerToElement(i)` (in practice it will be a more convoluted variant of that, maybe introduced by dozens of people working on a badly documented code base over a decade or two). I'd expect if programmers already do that in C++ there isn't much that prevent them doing that in unsafe rust?
> insane approach
I can assure you my mental health is pretty good, thanks. Though I made a comment regarding a thought experiment in a rust thread, I can see why you would think that.
The problem you're describing still exists, though I'd say the advice isn't quite right.
Generally the better advice is to use a graph library, or something like slotmap [1] if you're rolling your own, than to use a Vec or HashMap. That's superior to a vec/hashmap for a few reasons. It handles keeping indicies stable/writing your own index allocator. It also makes it possible with a feature flag to detect all use after frees at low-ish cost (instead of only detecting them if no-one is re-using the slot). It makes it convenient to use typed keys instead of integers. The underlying datastructure is basically the same though.
You can also use Rc/Weak for cyclic data, for ref counting "GC", it's an approach I have less experience with so I can't speak towards it as well.
In the end not that much data is cyclic (especially in idiomatic rust), and this is trading off a small amount of debugging convenience on cyclic data, for guarantees of memory handling correctness in the rest of your code, and for guarantees about the amount of damage that mistakes can do in the code that does need to handle cyclic data (which in turn is a debugging win on cyclic data, so...).
I agree it's a bit of a rough edge, but it's a case where rust solved the easy 95% of the problem with only slightly questionable tradeoffs on the remaining 5%, and that's a win in my book.
While I think there are valid arguments in both directions for putting more things like this in std, I don't think "non-bug issues have been open for over a year" is one of them. The exact same is true of std.
IIRC in Rust this is a little bit looser than elsewhere (let's say in C++) as the ABI is not stable. This allows improvements that change the internal structure of structs but not the API. As a counter example, in C++11 there was a breaking change that introduced a size field to std::list, making size() O(1) instead of O(n), breaking linkage between older and newer versions of C++ binaries. In Rust there is no such guarantee so changes like that could be introduced anytime.
The absence of versioning hell with Rust is one of the many things I love about Rust.
Of course if it appears in an old version the author won't bother to backport the fix so you will have to bump the dependency to the latest, doing all the API changes that you didn't want to do.
rust is one of them.
It's been a long time since I've been able to write anything in Rust despite loving the language. My last hopes for Rust are now in gcc-rs splitting the Rust ecosystem into two; the current npm-style crates.io ecosystem and a more destro-centric properly vetted package ecosystem. If this doesn't happen, I'll just continue to use other languages or limit my dependencies to those with sane package management (usually this means libraries written in C) until something better pops up.
Has there been discussion about this here on HN or an article about it you can point me to? I'm very much interested in exactly the same thing.
Rust being a low-level library, adding something means inherently choosing a preferred approach to a problem rather than another, which may be disagreeble.
The consequence is that there would be still the sub-sub-dependencies problem, because the author of a crate may decide that the stdlib implementation is not appropriate for the use-case (Rust is low-level; low-level development is typically "pickier" than web development).
I personally think that it's good not to have higher level APIs in the stdlib. My only exception to this is the exclusion of fast hashing, because this choice had side-effects beyond simple need for an API.
Having two distinct "products" could help here. There could be a "bare rust" that is minimal and unopinionated, and used by those that need a small footprint, for example. A "battery included rust" could have common solutions to common problems that are hard to solve with "bare rust", at the expense of making choices that are best avoided for "bare rust".
My current outsider's perspective is that there's some kind of ever-shifting, never quite established consensus on which batteries to include, which tends to make it harder than necessary to switch project, interoperate between libraries etc.
There is already, it's the nostd.
They don't have to download and install version 1 of an API for backwards compatibility if you're on version 2, and you don't have to download a new compiler version to upgrade a package as long as the package's maintainer is still willing to support the version you're on.
(That latter one being the same as with support for new revisions of C or C++ in in GCC.)
Last year has been a bit rough and I didn't have a whole lot of free time and energy to work on projects at the same time.
That said, I don't believe any of the open issues on slotmap are of immediate need of attention, they are mostly minor feature requests/incremental improvements.
I do have a slotmap 2.0 in the planning that will include most of these improvements and allow further customization and control of the number of bits used for index/generation as well as what to do when the generation would wrap around (either leak that specific slot or allow a spurious reference with a (very) old key).
The advantage w.r.t plain Vec and juggling integer indices is that unlike integers, Slotmap keeps track of the "identity" of the stored object; the keys are unique to that object, and you can't accidentally refer to a wrong object with them.
> errors risk being silent references to wrong objects
Slotmap is specifically designed to prevents this. I recommend you to read its documentation; the generational indices system is quite nice!
(I am not sure if slotmap uses this strategy)
To give more details some of these data structures use generational indexes, a pair (generation, index) where index is a plain index of the underlying vector and generation is a bookkeeping counter of how many times you have allocated a value to that index. These two values can be combined in a single 32bit-64bit value but additional memory would be required to keep track of the counter.
E.g. with a vector of length 2
{meta: [0,0], data:[...]}
malloc -> (1,0)
{meta: [1,0], data:[...]}
malloc -> (1,1)
{meta: [1,1], data:[...]}
free(0)
{meta: [2,1], data:[...]}
malloc -> (3,0)
{meta: [3,1], data:[...]}
free(0)
{meta: [4,1], data:[...]}
malloc -> (5,0)
{meta: [5,1], data:[...]}
free(0)
free(1)
{meta: [6,2], data:[...]}
malloc -> (7,0)
malloc -> (3,1)
{meta: [7,3], data:[...]}
This way if you tried to access the pointer (5,0) the library can check that at index zero of the meta array the generation is 7 and conclude that you are doing a use after free (in this example even generations denote unallocated memory).
This is a description of a very simplified algorithm.
A generation count indeed could mitigate "use after free" style bugs, but may have a high false negative ratio if many/most objects have same generation. But a glance at slotmap docs didn't yield any hits for a generation I'd being used, do you have a specific link?
The main problem with reference counted pointers is detecting cycles. Rust doesn't have a cycle detector, but only a concept of "weak" pointers that don't prevent the object they're pointing at from being destroyed, just detect if it has been. This works fine if you have a tree with parent pointers, you make the parent pointers weak and everything works. It doesn't work so well if you don't have a clear tree structure though, because then you can't really tell which pointers should be strong and which should be weak.
> but may have a high false negative ratio if many/most objects have same generation. But a glance at slotmap docs didn't yield any hits for a generation I'd being used, do you have a specific link?
Apart from wrapping around after 2^32 frees of a specific slot, I don't believe any false positives are possible. The trade off is that there's more overhead than I think you're imagining.
https://docs.rs/slotmap/1.0.6/slotmap/#performance-character...
Once I get around to slotmap 2.0 (as noted by my inactivity, I haven't had much of the good free time + energy combination last year), the default behavior will be to leak the memory of a slot after 2^31 alloc/free pairs in that slot rather than wrapping around. You can still get the old wrapping behavior, but the default will be to never, ever allow spurious references, at the cost of leaking a couple bytes of memory once in a blue moon if you have heavy, heavy churn. That means, amortized, each insertion will leak 3.726 nanobytes if you're storing u32s, which is a fun unit. Note that if you destruct the slotmap the memory is reclaimed of course, I just mean that slotmap itself will not use that piece of memory again.
> The trade off is that there's more overhead than I think you're imagining.
I don't think the overhead is as large as this implies. For SlotMap the memory overhead is ~4bytes plus alignment per element, and insertion/deletion is only a handful instructions and one branch extra compared to a vector push:
https://docs.rs/slotmap/1.0.6/src/slotmap/basic.rs.html#349
An index adds one extra branch compared to a normal index:
> I don't think the overhead is as large as this implies. For SlotMap the memory overhead is ~4bytes plus alignment per element, and insertion/deletion is only a handful instructions and one branch extra compared to a vector push:
I think they were imagining one generation counter for the entire map instead of one per slot. I agree it's not particularly high.
For trees without parent pointers: Just roll your own along the lines of the following. This fits nicely into rust's ownership semantics
struct Node<T> {
children: Vec<Node<T>>
}
For trees with parent pointers, I'm not sure what's most common. Potentially Rc with Weak, potentially petgraph, maybe something else.I'm even having a hard time seeing how this could be slower than any other alternative. Yes, in the places where creating / deleting is necessary, the "root" structure will have to be passed around, but in the worst case that has the cost of adding one argument to a function (which has the nice side effect of making the lifecycle _visible_).
This is, however, an optimization. I rarely write my code like that on the first pass. It's something I always have in mind that at some point it's worth replacing the pointers.
(This is not specific to rust, or any other language)
Though in Rust it has another advantage over pointers: it doesn't force you to suddenly annotate every single type that touches your data structure in any way.
Or worse, actual data belonging to someone else. If the integer is a user id, and you delete an user, reuse it for another user, the former user might see data for another use. That is a big security issue
Out-of-bounds array accesses causing segfaults is the happy case! The sad case is security vulnerabilities.
I would agree that using naive integer indices, and running the risk of accessing the wrong data, is also completely unacceptable, though.
(You're right that it actually doesn't always work because sometimes your stale index will still be inside the array but refer to a different thing, but at least it can't be abused to write into other arrays).
I know this is out of the blue, but I really want to get in contact with you. Thanks.
You cannot do cyclic data structures in Rust because every thing must have one owner, so no cycles.
You can do cyclic data structures in Rust with unsafe code or doing your own memory management (e.g. an arena data structure).
> The borrow checker worked fine when all I needed to do was pass data up and down the callstack, but anything beyond that was difficult or impossible to express
That is not true. It is true at the start of the learning curve, but you get used to it. Cyclic data structures are very far from simple.
Unsafe is there if you need it. It gives you C pointers for everyone and their debugger to blow up on. The difference is Rust makes you painfully aware that CS 101 is actually hardcore engineering.
This is not correct advice; not sure why you've been given this answer.
There are a couple of solutions.
1. you use a data structure (library) that returns you a handler, which can be an int, but it's not an int as in "position inside a vec" (index), but a symbolic reference, whose management is deferred to the library.
You can't use an index directly because if a position is freed, then taken, you will hold an invalid reference (int).
This is a handy solution, convenient to work with; if you do something wrong, you'll get an error from the library.
2. the manual solution is to use strong/weak references, which are quite ugly to use :)
I worked in C/C++ for a long time, though it’s been a while now. I just went to look at whether Rust had any bindings for MPI. It does - rsmpi. But they’re not fully implemented, and only support a restricted subset of MPI implementations which are pretty much the latest versions. Some others might work, but it is not explicitly tested against them. Without that, there’s a whole class of distributed applications that you’d be ill advised to write in Rust using that library, because it’s such a fundamentally core library for distributed applications, which needs to be compiled differently and with specific versions to handle the specialist interconnects on HPC systems. If you only support the latest versions, your code is not very portable to other machines.
But if you do have the freedom to choose, then I don't see why anyone would really pick C++ over Rust at this point.
Most of us don't have the funding, skills, time, priority to rewrite all of our old web forms apps even if we wanted to. Who is going to pay to rewrite the app that only earns us $10K a year?
Even if we did decide that Rust is great, do we immediately expect our C++ senior devs to produce the same quality code in a language they have only just learned? Are we going to recruit some confident youngsters who possibly know Rust but haven't been burned enough times to be pragmatic when implementing it in the wild. Do we want to rely on a new language that ticks lots of boxes but also lacks the understanding/support and battle-testedness of C++?
The amount of global manhours MS is throwing down the drain by constantly ending support for their versions must be absolutely staggering. Updates are often far from trivial, and they expect everyone to keep up with their fast upgrades and tiny support windows? Long term support is only 3 years, are you kidding me?
No, they are actually trivial starting from 3.1/5/6 exactly because of the work they have put in.
And sure, upgrading from .Net 5 to 6 was trivial, but do you really anticipate it will now finally remain stable for eternity? Give it two or three minor versions and they'll have come up with something else to break 90% of your dependencies.
He's not suggesting rewriting anything. He explicitly said "it's time to halt starting any new projects in C/C++" (emphasis mine)
C/C++ isn't going away, old C/C++ things can remain as old C/C++ things.
Until rust catches up with some meaningful feature set that Qt provides starting a GUI project in rust is probably going to be painful.
https://github.com/tauri-apps/tauri uses OS provided WebView
https://github.com/sciter-sdk/rust-sciter uses Sciter
But Qt provides that…
tauri has exactly 1 release, that was done 4 days ago.
sciter has done no release in over a year, and has 6 releases total.
It would be completely insane to pick either of those instead of Qt.
If someone is a Qt and C++ expert, then maybe, but it still seems like an uphill battle compared to web stuff, which to me seems better supported on all platforms.
Using a cross-platform backend + UI stack seems like a best of both worlds. ~5 years ago we developed a kiosk for car washes (you could buy a membership online, then use the QR code, but it had also devices to accept coins and banknotes), backend was Rust, frontend was Angular (the kiosk ran Firefox kiosk on a touch screen, and there was even a tablet at the counter that ran an app that was a bundled webview basically).
It worked well on different devices in different sizes, updates were as simple as "yes restart the thing".
Interestingly we had a C++ project shortly before that (number crunching for music recognition, so not really something that you'd do without a high performance language). We picked Rust for the next one because it seemed easier to implement the state machine required to manage the connected devices & clients in it than in Python.
I absolutely don't miss C++ or Qt (or PyQt, or MOS files, CMakeLists.txt shudder)
So offering these shops to consider Rust or any other "it's better" language is similar to Enterprise Java push back in time, which simply turned local weed gardens into weed prairies with even wilder variety.
Meanwhile considering safe practices and features of whatever modern C++ is a normal and indeed organic process for such organizations, be it for new or supporting the existing projects.
As for starting an "independent" new project, well, that's a whole new story. I guess the choice would still rely on the need and availability of external components for it. Ah, least we forget about the costs!
I hope so. I have a hypothesis that the big-O for language success is "How easily can new programmers learn it?" Nothing else matter. JavaScript was slow, but everyone learned it, so it got fast. Python still had bad tooling, but everyone learned it, so it got better. And C got popular in the first place cause it was easier than assembly.
I wanna ask my managers if we could try hiring Rust devs. I don't like hiring people fresh out of college, but I can't manifest more money to hire experienced C++ devs. If the pool of good-enough-Rust devs is growing faster, and maybe already bigger than the good-enough-C++ pool, why am we interviewing people who don't even know what they don't know about C++?
Also the truly tricky things in Rust are relatively few and can be escaped with an unsafe.
... But it can't shed the old stuff without breaking backwards compatibility, and that's what bites you. The fact that smart pointers exist now doesn't stop a developer from passing around non -const char* with no size specifier and calling that a "buffer," and because the language is so old and accreted most of its safety features later, the shortest way to express an idea tends to be the likeliest way to be subtly wrong.
This is really just a problem that other languages don't have because they didn't have the same starting point.
If your developers are coming to the table with some C++ tutorial books written a decade ago, good luck. Invest in a decent linter and opinionated format checker.
I can't imagine anyone ever describing vanilla JavaScript this way.
It really draws into question the claim that “it's easier to write super complex stuff in C++ than in Rust” when so clearly incorrect about JS. Especially when we have _decades_ of evidence from world-stopping vulnerabilities in the C/C++ ecosystem.
As someone who was writing both in the 2000s: PHP fits this "nicely" haha
Surely you can describe this with more than a throwaway sentence, given that more and more people are seeming to experience the opposite.
>Like JavaScript, yet another language written for bad to average developers to keep them from shooting themselves in the foot.
Nobody would describe JS this way - the entire existence of that language is filled with projects attempting to make it better for "bad to average developers" because it is certainly not what you're describing.
Edit: minor formatting of quotes.
That hasn’t been my experience. Rust (the language) doesn’t seem to get any more complex as programs get bigger. Lifetimes, while complex in isolation, tend to compose really well.
Most of the pain of learning rust seems to be experienced up front. (Well, other than async but I don’t consider that ready yet).
In comparison, my experience of C++ was that it has way more “spooky action at a distance”. A bug in one part of the code will cause problems in another totally unrelated part of the code. I’ve had memory bugs in C++ which took weeks to track down. Maybe C++ has gotten better - I haven’t touched it in over a decade. I haven’t wanted to. And I can’t see many reasons I’d pick it up now that I know rust.
Not sure how limiting the discussion of a language to just the features included in the 3rd standard and forward makes sense. Particularly when the old stuff is still present and valid in the later standards.
Just because you want to use some convention curtain off some area of the language doesn't mean it's not there.
This came 2 years after C++11 was finalized, which introduced RAII memory management, threads, range loops and much more, and is the basis for modern C++.
Of course, there are pros and cons to keeping backwards compatibility with old code. Personally I think it's an amazing technical achievement that the same code written in 1987 still works. Particularly for numerical work there are a lot of libraries that would be a massive pain to rewrite correctly, just getting them off of Fortran was an achievement.
In terms of new and old standards coexisting in the same code, of course it isn't preferable, but it is possible which can enable many use cases, eg. in place upgrades. Forcing rewite-the-world is what caused the Python 2 --> 3 migration to be such a mess.
And if you really don't want old features, there are linter rules and compiler warnings which do a great job for this.
Look into rust's editions. Short version: any compilation unit[1] can declare which edition it is written for. The code in that unit must be valid under the rules of the edition, but different units with different editions can be compiled into a larger program.
https://doc.rust-lang.org/edition-guide/editions/index.html
[1] the compilation unit in rust is a crate. That doesn't mean it has to be put into crates.io, just that it has to be cordoned with its own Cargo.toml and any non-public structs/functions/etc will not be accessible from outside the crate.
With the new GCC Rust work I believe a new solution will need to be found, and it will end up more similar to the situation with C++.
As someone who isn’t a rust native but an interested outsider, it can obviously be cumbersome to use on my pet projects compared to something like python, js, c# or C. Dealing with references to generically types traits adds a lot of syntactical burden (re: shit for me to type) and defining types and their implementations leaves something to be desired regarding its grammars.
That being said, my toy programs do not require particularly complex types and the rust compiler is nothing short of a brilliant. The book is a surprisingly easy read, the module system is fine, cargo is decent out of the box, and there is an interesting mix of paradigms in the language itself. In my mind, the power of the compiler is certainly the big feature of rust and that compilers input language is decent enough such that I wouldn’t dislike using it as a daily driver.
It keeps you from compiling (many of) the bugs you'll happily write and deploy in C++. I don't think there's really much practical difference in "cognitive load" between modern C++ (which is painfully complex in ways that are largely not even useful) and rust. C++ just lets you pretend it's lower and you ship more bugs.
Imo, writing rust is like the best parts of writing C++ with a stern but helpful assistant.
Anyways, unsafe exists so that if rust is genuinely in your way you can still do what you need to do.
Other than the fact that rust can rely on much much stricter aliasing rules and do a bit better on some optimizations because of it.
Usually when people talk about rust getting in their way they mean the borrow checker, which you can ask to get out of your way and it will still prevent bugs around the unsafe code. Bugs that "advanced programmers" are also prone to, especially around concurrency.
The idea that some programmers are so good they don't make simple but consequential mistakes in code that deals in concurrency and memory management is absolutely elitism.
There is no programmer on the planet who can't benefit from the borrow checker, and if there are any who will benefit less than they are "hindered" by it, there are almost certainly vanishingly few.
And so what if Rust is lowering the bar for entry to systems programming? I'd much rather fresh ideas and fresh blood enter the field, than it slowly dying as the only people with arcane C/C++ knowledge slowly retire/die.
Unless you meant actually all of Rust. In that case, please share what's inexpressible in Rust.
At the most basic level, in Rust you cannot overload operators. You have no opportunity at all to code a move constructor. I could list off others all day long, but you probably would not understand most.
Then there are the things the borrow checker will not let you do, that would be correct, but it can't see that. You might say you can put those in "unsafe", but you can't really field a library where users sometimes must put a call in unsafe.
It is easy to insist you have never needed any of that stuff for your library, but that is really because you have constrained what you even think of trying to do by what you know you can do. We box ourselves in this way automatically, and it takes great effort to break out of such a mental box.
I've heard this claim multiple places and I don't really understand it. Operators have corresponding traits that you can pretty easily define for your types.
SQL builder programmers, for example, wanted assignment operator overload.
However, I'd argue that it's the wrong kind of overload to enable. The more code can do behind the scenes, the harder it is to reason about it, e.g. :
c = b;
Is this an assignment? Will it start the DB connection? In Rust, it can be just one thing. By sticking that code in proc macro and translating code, you signal your intent that something funny is happening here and that you should consult docs for more info: sql!(a = b)
> It is easy to insist you have never needed any of that stuff for your library,I didn't say it was easy. I didn't say it was impossible either https://mcyoung.xyz/2021/04/26/move-ctors/.
> Then there are the things the borrow checker will not let you do, that would be correct, but it can't see that.
Sure, but that's the Rice theorem at work (https://en.wikipedia.org/wiki/Rice%27s_theorem). Any non-trivial property of code is undecidable. That's why you have the unsafe escape hatch where you reason about why it's safe.
[1] which isn't that different C++ which prohibits some operator overload, but in C++ the list of operator not overloaded is small
I gave you a working example of operator overloading in Rust a while ago.
Why do you still state that Rust doesn't allow that? Is there a problem with the example?
I know a lot of different languages and have a feature matrix for reviewing them, and I would know if operator overloading didn't work since it's a row in there. It definitely does work in Rust (it's similar to Python's operator overloading).
I've written Rust professionally and would rather write Rust than C++. That said, almost every concept you need to understand C++ is also needed to understand Rust, but then Rust adds additional complex semantics that aren't going to be intuitive to novices and don't trivially map to either other common high-level languages or obvious low-level concepts.
Good riddance.
C++ will still be used heavily when Rust is buried 6 feet under and HN moves to the next hype language.
If you're working on a substantial C++ codebase you probably do, actually.
Eh, all these "different string" are different because... Well, they have different requirements. Path is not a normal string, it has platform-dependent implications, String/str are UTF8 strings, the byte-esque string have raw bytes, etc. I know I'm being brief, but I hope the differences I'm trying to illustrate are clear, and why it makes sense for these to be different types.
> arcane borrow checker workarounds
You often end up with these in portable/cross-platform C++ or in performance sensitive C++ code. Also, if you've not burdened yourself with OOP-style thinking and adjust your expectations to the fact you're not writing C++ anymore, but a different language, you'll have an easier time learning Rust. All that said, what you call workarounds is probably idiomatic to Rust developers. And even in the most pathological case of workarounds, the resulting Rust code will be much more succinct than any back-breaking efforts to make C++ readable/correct/performant (two of which you get for free in Rust; sans some complicated domains). Like, as examples: just working with std::variant is a nightmare and requires grotesque constructs with visitors patterns (and often lambdas), std::option is a joke that's marginally better than a raw pointer, etc.
> RefCell complexity,
It's no worse than just working with borrowing, and it's not that often you'd use this anyways.
> massive async cruft
Yes, you have a point here, and everyone's aware of this. And people who have ideas in the community about how it can be addressed can easily participate in the discussion and design process if they desire. Whereas C++ is designed by a committee of people who only barely still use the language in the real world (I know there's exceptions, but alas).
Also, if we got tooth for tooth, C++ has an abundance of more complexity than Rust does, and a lot of it isn't even obviously (hence can be dangerous, or just ruin your day/productivity)
have fun living your life pretending all strings are of the same type. spoiler alert: it's the wrong kind of fun. it's a bit easier if you're from a native English speaking country, but only until you get blown up by utf-8 (if you're lucky) in production.
1. Exception safety becomes "catch_unwind." You might object that nobody cares about that, but major C++ codebases (Google, LLVM, Mozilla) don't care about exceptions; they are built with -fno-exceptions.
2. Move semantics in C++ are annoying, and so is the borrow checker. In Rust you get hit by things like "this code is fine here, but you aren't allowed to refactor it into a function" because there's no interprocedrural visibility into struct fields.
3. Meta-template higgery-jiggery is real and bad in C++, but has a mirror in Rust. With C++ duck-typed generics you write dumb code that does the thing, and then you can refine it with hilariously awful techniques like SFINAE. In Rust you're googling higher-ranked trait bounds before you can even write the thing. What does `for` do again? I think "strongly-typed language, duck-typed generics" is a bit of a sweet spot and C++ has lucked its way into it.
4. "30 years of cruft" means things like "I speak C preprocessor" which is practical. C compat is why C++ is both so awkward and so successful. There's no smooth ramp from C++ to Rust, the way there was from C to C++; that's a choice and maybe the right choice but it has a price.
With concepts in C++20, you get to choose whether templates are duck-typed.
I sometimes just wish I could punt to Tokio. Why am I managing threads? Threads are an implementation detail!
I see it as, Rust tells you about the complexity and helps you with it. C++ waits until you trip on it, and then tells you to use Valgrind.
I could be wrong, though. Or I could be 5 years too early.
I agree that many basic C++ concepts are also present in Rust, but C++ is more than just its basic concepts: it's a huge set of features on top of those that interact with each other in complicated ways. Like how constructors aren't functions but something very special. If you just want to be a beginner C++ dev who works alone on their piece of software that doesn't have any dependencies, you can be fine, you just use the subset you are familiar with. But if you want to maintain other people's code, you need to fully understand what it is doing, the C++ features it's using. Rust's whole feature surface is absolutely smaller than that of C++, and the features that exist integrate way better than the C++ features.
Plus, if there is a gap or misconception in your knowledge, in Rust you would get a compiler error, often very well explained. In C++ you would get a segfault, often not a really nice one.
Long ago C++ made C a little bit more complex. Because there were already lots of C programmers that wasn't a big deal.
But then it didn't stop. Little by little C++ grew into a monstrosity. A lot of people went along. I gave up.
For new programmers to climb in 2-3 years a mountain that seasoned programmers took 15-20 years to climb is asking too much.
Yes, I'm exaggerating, a bit.
As for the Microsoft whomever-he-is: I agree in theory, I disagree in practice. If there are a lot of C++ devs writing important code, then let them continue to do so in their prime language that they've invested decades of hard work keeping up with the feature treadmill. New devs? Only if you have to.
Let me put a more pro-C++ spin on that sentiment.
C++ is a language that's under long-term development. It might sound weird, but only with C++20 Bjarne Stroustrup felt that his vision for the language was now mostly-realized - and he had worked on it since the 1980s. With other languages, there's a lot of clearing-of-the-desk and starting things anew, while C++ has opted for incremental changes with backwards compatibility to before it existed (i.e. C).
But, looking back, we get the sentiment you describe. Which, rephrased, sounds like this:
"Remember that annoying and ugly hack you had to use so far to get [complex thing] to work? Well, that finally got fixed. Now there's a shiny new language feature / standard library construct which does that more nicely. But your existing code will also work."
Then we had concurrency primitives, and now apparently there's a module system in c++20 which should be interesting. C++ clearly has no plans to bow out gracefully or otherwise go quietly into the night, which is fine by me since I still think it's the language which gives me, as a developer, the most freedom and control over the system.
So... let me ask you given this statement. Let's say there is an uber smart super productive programmer who states: I can rewrite the entirety of the ecosystem of one language in 1 year....
Would you tell them to rewrite all C/C++ in C++20
or
Rewrite it in Rust?
C++'s only real advantage in the current language marketplace is an installed library base. But how much of that is C++0x2020? Is the barrier to entry of a new programmer in C++ not just 40 years of language revisions, but a massive massive map of libraries where JSON library uses features from v2016, while XML library uses v2005, while some multithreading thing uses v2020...
And then there's the STL, and mixed-in-C standard library, ye gods.
Will Rust turn into that? Well, I think it kind of will to some degree as they try to find dialects that perfectly describe borrower checker semantics. Rust is a syntax soup almost on par with C++, but I guess we'll see.
Neither.
1. I wouldn't trust a person who says something like that. It takes a programming luminary several years to write a good (non-trivial, not-tiny) library the community can get behind, and even that usually involves iterations of use, feedback and partial rewriting/redesign.
2. Why would we want a "rewrite of the entire ecosystem" (whatever that ecosystem may be) all at once? That's a fiasco waiting to happen.
3. An "ecosystem" very often needs to be at least somewhat backwards-compatible, so I wouldn't want it written in something that's just out of the nylons.
Probably best to let that smart programmer write some decent foundational libraries which we can adopt one at a time, with increasing benefit of synergy.
> C++'s only real advantage in the current language marketplace is an installed library base
That seems untrue. C++ has various capabilities in different usage scenarios which other languages do not. But more importantly - programming languages don't all compete: They typically have different combinations of design goals. That's specifically true of C++ vs Rust.
> But how much of that is C++0x2020?
That doesn't matter much. For you, anything that's not written in the latest version of a language may be irrelevant/unusable. Not for the users of backwards (and forwards-) compatible languages like C, C++ and various others.
> Is the barrier to entry of a new programmer in C++ not just 40 years of language revisions
No, 40 years of revisions is not a barrier to entry. Your saying that makes it sound like you are not very familiar with the language.
> mixed-in-C standard library, ye gods.
double x = sqrt(x_squared);
... oh, the humanity! Who would ever write something like this? It's a non-polymorphic function and its symbol doesn't get mangled! Ye gods!
At lastjob, we did a lot of C++, and I could tell whose code I was reading without checking blame because I knew who liked what idioms and features.
Amusingly, this was always the criticism I've seen leveled at Lisps over the years. It's just as true in C++ for sure.
1. I got a couple of downvotes a few days ago because I commented that I don't like the &s of Elixir (kind of shortcuts for 'fn x ->') and I prefer to write the full form as it's easier to read for everyone no matter how proficient in the language (zero to expert.) I also don't like and almost don't use the & shortcuts in Ruby (positional arguments.)
2. I got a customer recently with the lead developer fond of each_with_object. I never saw that in 17 years of Ruby and I had to check the reference. It's probably faster than the naive implementation (more time inside the C implementation doing real work vs inside the C parser?) but the naive one is immediately readable by anyone.
While I absolutely agree with this in general, in practice with C++ if you're trying to use it safely you do in fact need to use those new features. But the old features are all still around too. It's a very, very large language in terms of mental space required these days.
Rust was by far easier.
That said - that’s an extremely biased statement and I recognize that. I think it was largely the compiler that helped make it easier.
That said code in C++ would just vomit cryptic messages about templates and SEGFAULT nearly all the time.
What I'm trying to say skill floor - minimum skill/time needed to learn something to do it however in Rust is higher than C++. Although not in the sense of you must be this smart to enter, but you need this much time to learn it. If I can learn it, and I'm a mediocre programmer it's not an issue of skill.
That said skill ceiling - skill needed to do it efficiently and without error is much higher in C++ than in Rust.
Things that Rust does that makes things easy for me as a less-experienced non-systems programmer:
- very good documentation and compiler errors
- cargo makes dependency management and distribution a breeze (big plus over python)
- footguns are easily recognizable and avoided (unsafe)
- strong typing allows me to express more invariants in the type system which makes my code easier to reason about (another big plus over python)
The borrow checker can be an impediment at times and I'm probably leaving some performance at the door by generally avoiding references in data structures. I've found that this is less of a problem over time. It can also be way more verbose. But I have way more confidence that things will work at the end of the day, which makes it worthwhile for me, even if on the surface it is take longer and be harder to write than python.
It doesn't actually make for a good argument.
C++ makes more sense to me than Go or PHP. And probably Python.
You can get comfortable with some idioms of C++, that's fine. Can you understand what any valid C++ code means? No. Such person does not exist, not even Bjarne.
C++ is a mine field. You need to learn where all the mines are and spend your day carefully walking around them.
Some languages (like C) are easy but using them is hard.
Time to be reasonably sure your multi-threaded code won't crash randomly: Takes ages longer in C++, even if you're experienced.
If you read the whole spec, it looks super complicated. But getting to a mental model that works in 99% of cases is not _that_ hard.
Am I spending 2x of the new hire's time making them learn a harder language? Am I spending 2x of a senior's time teaching the new hire?
What's the payoff in sticking with C++? Better libraries? Better tools? IDEs? That stuff will all shift as time goes on, if popularity is against it.
Time goes on, business changes and computers become faster.
At some point, many developers started to see features like a garbage collector, become a good offer with few disadvantages.
Unless we really need the performance, do users really care if the program consumes a few cycles more, if those cycles are being spent on tools to make lives easier for developers, like a garbage collector?
90% of software wouldn't make sense to be written in C
This is my standard stack for C++ and last time I checked Rust couldn't do any of them. This is also my standard stack for building new open source computer vision libraries, growing the available libraries and making my field more locked into C++, increasing the moat Rust would need to cross.
Next step, can I compile and deploy for Windows, macOS, Linux, Android and iOS? All of these are critical business requirements. This is whether I can adopt Rust in my employer's codebase.
Finally, can I easily find and hire engineers who can read and write Rust who aren't asking FAANG compensation levels? This is the blocker for Rust in startups.
The worst part about Rust's cross-platform compatibility and cross-compilation is Rust's dependence on a C linker and C/C++ dependencies if you choose to use them.
For the most part CMake handles the cross platform toolchain issues, so it's just one flag to turn on Release Vs Debug builds, enable LTO, include dependencies etc. Again, it's just platform specific features that require if...endif sections.
The complaints I'm seeing here would be the equivalent of me complaining about Rust's garbage collection, the only difference is that Rust broke everyone's code in removing it while C++ managed to keep almost everything since the 1980s still working.
I have been writing C# almost exclusively for around 20 years and I am still learning tricks/tips/gotchas and not just for new language features. That is why my experience is important. Even in something like Java which looks very similar to C#, it takes a long time to work out what works differently, good patterns and idioms, the correct libraries that everyone uses for stuff etc. even when I know what I am looking for.
When I looked at Rust, I got some of it because I have previously written C and C++ and didn't have a problem with the concept of pointers or references but it still took me several weeks to get a basic example working and I had to ask on a forum in the end.
So yeah, not easy!
Just more anecdata, but this isn't true for my company. We're hiring for Rust because we're seeing more and more clients take memory safety seriously (and ask specifically about it as a design consideration).
These things have a way of balancing themselves out: developers like Rust, so there will probably be an eventual "glut" of Rust programmers like there was for C++ programmers in the 1990s. But it's a multiparadigm language, so I don't expect there to be consistent wage deflation based on that (and especially not in systems, where finding competent engineers is a perennial problem).
Running your test suite with asan, msan, tsan isn't sufficient? From my experience you need to start doing really nasty things (which shouldn't pass code review) before the sanitizers won't find your issues.
But that’s sort of tangential: the goal is to write software that’s correct to begin with, not poke holes in it with the testsuite after the fact. With Rust, I can pick third-party dependencies that I can be (vanishingly) confident don’t have memory safety issues; when I start a greenfield C++ project, any dependencies I bring in are now potential sources of memory unsafety in my code.
In other words: I very rarely write unsafe code myself. When I bring in others’ unsafe code, I use cargo-geiger and siderophile (which I help maintain) to quantify it.
Or such bugreports would make no sense: https://github.com/denoland/deno/issues/15020
This is exactly the same as in C++, except stronger: in C++, any piece of well-formed code can violate safe invariants. In Rust, only unsafe code can violate safe invariants, and can only do so if it isn't itself well-formed.
> so long as the only unsafe code in a well-typed λRust program is confined to libraries that satisfy their verification conditions, the program is safe to execute.
I think the main caveat is that IIRC, the RustBelt unsafe rules do not cover ALL uses of unsafe in the wild, they analyze only a subset of Rust as whole, and of course, unsafe usage actually has to obey the rules. But I'm hardly an expert here.
That bug report basically says they broke the unsafe rules and thus the guarantee no longer holds (and there is UB).
> Program testing can be a very effective way to show the presence of bugs, but it is hopelessly inadequate for showing their absence. -- Edsger W. Dijkstra, "The Humble Programmer" (1972)
Re: Dijkstra, I'm not trying to prove that the code has no memory errors, I'm trying to make sure none get triggered in production ie. the difference between computer science and software engineering. If there was a simple and easy way to do behaviour proofs I'd be happy to use that, but coq et al. are a real pain.
The original purpose of Rust was to displace C, a laudable goal. But it is failing at that, because C coders are practically defined as people who will never switch to anything. (Any who might have did already.) So now the only hope is to displace C++ instead, and the propaganda machine is trying to paint C++ as equally as unsafe as C, which it manifestly is not, lying if that is what it takes.
Rust is a simpler language, with better characteristics. Memory safety is the a big selling point for the business people, but there is also a better module system, dependency management, better generics, no hidden memory allocation, etc. etc.
rust is lacking a ton of libraries.
And personally I prefer using a big thing like Qt which has classes for everything, rather than rust where I have to find a non-terrible library for every little thing.
Do you not see the difference?
I have spent strictly more time in the past five years filing compiler bug reports than chasing memory faults. Yet you say I should trust the compiler to make errors impossible. Are you able to see the flaw in your reasoning, here?
That strikes me as wrong in many ways. I think it means, exactly - "new programs should use a different language than C++".
I someone writing that might have been implying "hire me instead", but given the specific author is CTO of azure, i doubt they are angling for your job, or really any dev job.
Managers hearing this advice from the CTO of could possibly interpret it as "lay off our C++ folks, we're hiring for rust". Or they could interpret it as:
* We should switch to the new language, have the team train up.
* We should have the team start evaluating new languages (or rust specifically).
* We hire some rust folks for the next project to evaluate how it goes.
Any half-way decent management will know that the institutional knowledge in their existing dev team is worth a lot, and getting the new hires up to speed is rather expensive.
Sure crap management exists, but I've never had, nor known any who has had management so bad that they would lay off thier whole dev team over a tweet. I really doubt "lay off all the C++ folks" would be a particularly common response.
To the degree that management pays them any attention -- and a CTO parroting their advocacy in tweets (squawks?) certainly counts -- the threat is real. Other companies' management may be equally affected, in a degree more than just posting idle-hack tweets.
Against, the subthread topic is overbearing Rust advocates and, specifically, what harm they can do. Obviously nobody will "lay off all the C++ folks" just because Rust promoters would really like that, and as much as say so. But that is very far from saying no harm is done, or that no one is harmed by their extremist rhetoric.
1. If it was so obvious, why did you claim it to be true, and then double down?
2. I have yet to see anyone say or even strongly imply it. The closest I've seen is this thread wherein you take a lot of leaps in reasoning and a very specific path through a large possibility space to divine the true intent of a simple sentence.
But that difference does not make advocating it less bad, unless they are obviously speaking facetiously and expect it to have no effect. It is very clear people saying it mean it and want that to happen.
Azure CTO's announcement is a success for that advocacy.
Even if every C++ codebase wanted to rewrite itself in rust that effort would take decades and in the mean time we'd still need C++ devs.
The only people advocating for firing C++ all devs are the imaginary ones in your head.
If my employer announced no new C++ projects, that would mean, at best, a sharp demotion. I would be relegated to maintenance of legacy products. The kind of systems I make would no longer be written, because Rust is not up to the job.
You reveal that what you are doing is fully as nasty as it seems. You reveal that you believe there wil be no room for your language without first tearing down another.
So, anyone saying "no programs should be written in C++" is saying, exactly, that I should not be able to do my work, and that I should not have employment.
That my current employer will not necessarily obey such an instruction does not make the attempt any the less offensive.
You are a great case study in why the rest of us shouldn't comingle our identities with the identities of our tools.
[1] I did note that you changed it from "no new projects" to "no programs" a dirty trick that I'm only going to address by pointing it out.
So you are being dishonest in pretending to a distinction without a difference.
Switching from the legitimate "you should use my new language because it is good" to "you should demote everybody coding <otherlang> to legacy maintenance, and put us in their place" admits a very ugly fact about yourselves and about your beliefs about your language's legitimate prospects.
If you believed it deserves a place on its own merits, you would not be trying to tear down other languages to try to make a hole for it. It is disgraceful behavior.
You should be ashamed of that, and you should be more ashamed of calling people who object "delusional".
That is simply not any definition I've ever heard for a new project. You are assuming a binary of written or not written, and yet there are codebases that are incompletely written. That is what the parent means about ongoing projects that wouldn't migrate to Rust where you'd still be able to work on them, and who knows, maybe Rust won't overtake C++ and it'll continue, like many C projects have.
But that you have made yourself a "C++ developer," and not a developer in general who solves problems with whatever tool is best, does mean that whenever something comes along that threatens your identity, you seem to take it to absurdity, as the parent says.
I read it as: where can we find a lower cost (than C++) pool of developers.
It's not particularly conspiratorial. Companies are always looking to expand their labor force and good C++ devs can be very expensive, so why would you want start a new project in C++? Security is another aspect altogether...
I was a Rust v1 contributor. I have great hopes for the language as a replacement for c in systems engineering. However, I much prefer C++ 20 for the kind of work I do (scientific computing). Rust isn't a competitor to C++ in that arena, in my humble opinion.
> Programmers currently using Rust are superior to programmers using C++, statistically speaking
The phrase 'statistically speaking' suggests the collection of empirical data. Could you elaborate?
> People learn Rust because they love their craft.
If Rust becomes popular enough, this will no longer be any truer than for people who learn c++.
There's a lot of domains where Rust isn't an appropriate replacement. Notice I phrased it as "if you have the choice between Rust and C++". Often times because of libraries/frameworks you need, that may not really be a choice.
> The phrase 'statistically speaking' suggests the collection of empirical data. Could you elaborate?
I don't have data apart from two decades of screening candidates and conducting interviews. I've heard this from other people, including Paul Graham, and I've seen it in my personal experience. I probably should have chosen different wording to not mislead people that this is backed by hard data.
> If Rust becomes popular enough, this will no longer be any truer than for people who learn c++.
That's how it goes. Python was once a signal for finding better developers. That's no longer true.
The ratio of C++/rust jobs where I am (EU country) is 5564/54. And these 54 jobs are mostly in cryptocurrencies.
edit: numbers say I'm wrong, C++ is more mainstream than C#, C is more mainstream than Java: https://www.tiobe.com/tiobe-index/. I mean I doubt this source (it seems to indicate objective-C, which is all but superseded by swift, is on the rise) but it's at least one datapoint.
This doesn't change the argument about scarcity in general, but it isn't true that the few jobs that are out there are only in crypto.
> People learn C++ in college. People learn Rust because they love their craft
Wow... and rust programmers wonder why rust has a stigma? So I guess John Carmack is inferior and is not an ultimate craftsman.
Am I crazy? Isn’t that literally exactly what the person I’m responding to was arguing with respect to Carmack?
Here it is in context:
> So I guess John Carmack is inferior and is not an ultimate craftsman.
I didn't realize that their are statistics on what constitutes a craftsman. But I'm willing to change my mind. I'm very curious what those statistics measure though.
Edit: Not to mention like peteradio pointed out, what does a statistically superior programmer look like and where do those statistics live?
Of course, the flip side of that is with a smaller pool of applicants, filling the position may not be any easier. It is harder to hire a poor candidate though.
John Carmack has actually played around with Rust. But I would like to reiterate that when generalizing about a population based on statistics, you might be correct more often than you'd be wrong (.e.g. men are more aggressive than women) but you can still easily find individuals who are exceptions. That you can find an exception doesn't disprove the rule. You still have to treat people as individuals, and not as a population. That should go without saying.
It does tend to grate on people when you have developers from a certain community going and calling anybody that doesn't agree with their "One True Way" inferior and not loving their craft. This is literally the No True Scotsman fallacy to a tee. You're essentially saying, "Only a true programmer that loves their craft would use Rust. Clearly if you're not using Rust, you're not a true programmer". Yeah, sure.
I'll say this for the millionth time, I've seen great code in C++, I've seen terrible code in C++. I've seen great code in Python, I've seen terrible code in Python. I've seen great code in Typescript, I've seen terrible code in Typescript. I personally don't look at Rust code, but I'm willing to bet that there's great Rust code, and terrible Rust code. It turns out, the language is not the variable in this equation, it's the developer.
> That's my personal experience, I don't have hard data to back it up.
So, statistically speaking, you're making this up out of thin air.
> That you can find an exception doesn't disprove the rule. You still have to treat people as individuals, and not as a population. That should go without saying.
Exactly, which is why saying something like:
>> People learn C++ in college. People learn Rust because they love their craft.
Is such a radical statement. I don't see people from other programming language communities talk like this. It's amazing to me that people from the Rust community think saying things like, "If you don't learn Rust, it must be because you don't love your craft" is a verifiable fact.
I know it's a crazy thought to have, but maybe, just maybe, people can like different things...?
I actually think it is quite widely used in this small niche. Don't have any data to back it up and my newsfeed is probably biased.
We're exchanging opinions here without any kind of data to back either claim, but let me offer a contrarian view: people who learn niche-language-X because they love their craft are mostly younger folk with little experience in programming. My reasoning for this is that you get less and less time to pursue your love for a programming language when said love competes with love for your SO, your kids, and all the other things that happen to most people later in life.
It's anecdotal, but in my experience people who learn niche languages because of love or fashion are not the kind of people who will help write high-quality libraries for the ecosystem. For that, you need a stable, sizeable "middle class" - people who already know what their doing, who were able to evaluate the tool objectively, and who found a real value in it. Such people are not easy to come by: IME by the time they have enough experience, they mostly lost the eagerness to evaluate every shiny new thing that comes along.
> The hiring market is way better for Rust because it's not mainstream.
I would like to see the statistics you base this opinion on. In my experience (also 20+ years of programming here) this effect is more than offset by the small pool of applicants.
> Languages are tools, try to be impartial and pick the best tool for the job.
Yes. But you need to account for more than just technical features of a tool, like hiring or the opposition from the existing team to learning the tool. Choosing Rust when you have 20 seasoned, experienced C++ devs just because cargo is better than CMake... might not be the greatest of ideas.
I want people who have a history of picking the right tool for the job, and see their job as a team sport instead of a personal art project. Not a hiring manager, but I'd be more interested why someone with knowledge of Rust picked Rust over other options. Mere knowledge of it implies nothing of substance, and I've cleaned up too many mistakes in my career written by people who put their craft ahead of their mission.
I learned Fortran, PL/I and IBM 370 Assembly Language in College. I learned C and then C++ because I loved my craft.
Lmao. Not even close.
"Programmers currently using Rust are superior to programmers using C++"
Hahahah that's cute.
C and C++ aren't going anywhere anytime soon. Love them, hate them, want to burn them with fire, they're here for a long, long time.
Leaving that aside, I was still hitting Rust "oh look the developer of this crate on which the entire universe depends still assumes that everything is x86, and one of five operating systems" issues as recently as late 2021. Rusties of the world: your language might be ready to take up the mantle of C- it's you and your ecosystem that I question.
If Rusties want Rust to displace C... simplify your dependency chains. Get a build system that's easily workable without an Internet connection and recent TLS support. Make it easy for beginners to build out Rust infrastructure for OpenVMS on Itanium, Solaris on SPARC, z/OS, MorphOS, GNU/Hurd, and a 20-year-old budget PDA running a custom OS on an SH4 CPU. Make it feasible to get Rust everywhere that C currently is... then we'll discuss getting rid of C. Until then it's just wind.
Herb Sutter's latest proposal and, to a slightly lesser degree, Carbon are more interesting in that respect.
There's a world where Rust is as easy to use as C, C++, Fortran, etc. outside of cargo, but it's not an interesting use case for the Rust community to support right now for whatever reason. That's basically my point.
And it's common enough to have linked programs in which python calls C that calls C++ that calls Fortran that calls C. Replacing arbitrary layers with Rust is technically possible, though Rust doesn't tend to be deployed in situations like that, at least not yet. I'll consider the Rust ecosystem more mature when you see Rust used mixed ELF situations like that.
Yep. The Rust ecosystem is very much a product of the always-connected, move-fast-and-break-things, DevOps-CI/CD-SCRUM-Agile, horizontal scaling world... which is fine right up until the point where it needs to be used outside of that world, at which point all hell breaks loose.
It’s true that building Rust projects is easy with cargo and hard without. But how did you go from that to “move-fast-and-break-things”? Could you give an example of a broken thing?
Is the Linux kernel “DevOps-CI/CD”? Does Linus Torvalds manage the project in a “SCRUM-Agile” way? Let’s find out if “all hell breaks loose” when we get Linux 6.1.
C is welcome to that niche IMO. The priority is getting people to stop using C or C++ for regular applications that are exposed to the internet; if Rust can replace those use cases then it'll be job done.
But I think this is already been taken care of by Java and others?
I'll say typing `cargo build --offline` can qualify as "easily workable".
Nobody denies this, which is why one of Rust's main goals was supporting the C ABI, so Rust can use existing C libraries, or an application written in C can use Rust libraries.
> Leaving that aside, I was still hitting Rust "oh look the developer of this crate on which the entire universe depends still assumes that everything is x86, and one of five operating systems" issues as recently as late 2021.
I am curious. Could you give some more context?
> Get a build system that's easily workable without an Internet connection and recent TLS support.
Cargo supports vendoring dependencies and local dependencies.
> Make it easy for beginners to build out Rust infrastructure for OpenVMS on Itanium, Solaris on SPARC, z/OS, MorphOS, GNU/Hurd, and a 20-year-old budget PDA running a custom OS on an SH4 CPU.
When has it even been easy for beginners to build out systems infrastructure?
Progress is being made on allowing Rust to target more platforms, including `rustc_codegen_gcc` and `gcc-rs`.
Probably talking about this: https://github.com/pyca/cryptography/issues/5771
Anecdotally, I had the same issue recently with a C++ tool I wanted to tun on arm linux (forgot what it was; but it was a WASM tool. I ended up using a Rust alternative that was less mature, but did all I needed anyway)
Lastly, the issue you're describing is more of a DevOps one. C++ has a longer history, and one would hope it has accumulated more DevOps wisdom over that period of time.
Yep. My thoughts exactly.
> OpenVMS on Itanium, Solaris on SPARC, z/OS, MorphOS, GNU/Hurd, and a 20-year-old budget PDA running a custom OS on an SH4 CPU
what?
please don't
Based on the comments here, I see that I need to clarify two things, as edits are locked.
First, I actually happen to rather appreciate the Rust language itself. It is both powerful and pragmatic, and has quite a bit to recommend it. Even in situations where its addition has been personally very problematic for me (e.g. Firefox), I can still tip my hat to the added value. What I take strong exception to is Rust evangelism, i.e. the idea that Rust and its ecosystem are clearly superior to all other options in a given use case, and any person using other options must be either insane or uninformed. This represents, at best, a very narrow view of the computing ecosystem in the 21st century. My comment is a rebuke of the evangelism, not the language.
Second, the term "rusties" might have (reasonably) seemed like a label that I applied to any Rust developer. This is not the case, and the perception is a result of my failure to clarify. There is a particular class of person whom one meets, with whom any discussion of any technology project inevitably leads to "well you really should write that in Rust." Such folks- overzealous Rust evangelists- are "rusties" in my vocabulary. If that describes you, feel free to take insult if you like. If that doesn't describe you, then my apologies for any misunderstanding.
In fact, until LLVM is replaced, C++ will probably be the language of choice for new languages. Even `rustc` requires a C++ bootstrap for that purpose.
There are also other important C++ and C libraries that will continue to mean C and C++ may be better choices than Rust in certain cases.
And don't get me started on embedded.
Also, that doesn't even matter when the purpose is a hobby project (such as mine) where the programmer has no interest in Rust (such as me).
I like how Trevor Jim put it [1] better:
> If you decide to write your project in C/C++ you must have a plan for handling the inevitable memory corruption in advance. Anything else is malpractice.
This is possible to do. I've released a non-trivial program that has had no known memory bugs ever since 1.0 on 2018-10-26. It is written in C. And I challenge anyone to find one in any release since then. You might find one, but I think it will be tough.
In other words, it's possible to put C and C++ on the same footing as Rust when it comes to memory bugs; after all, even Rust is not perfect there.
Yes, it takes more effort. A lot more effort. For my hobby projects, that works fine because I'd rather work in C with the extra effort than in Rust.
Oh, and it's possible to make C as good as Rust: I've got macros to do automatic bounds checking. I've got RAII and stack traces. I've got structured concurrency, which will give the same capabilities as the Rust borrow checker if you adjust your coding style. And all this in portable C11.
So no, Rust is not the end-all be-all of languages. Sorry.
Rant about absolutist opinion over.
But seriously, use Rust if it's available for your target platforms, and you have no other preference.
[1]: http://trevorjim.com/using-an-unsafe-language-is-a-design-fl...
>I've got macros to do automatic bounds checking. I've got RAII and stack traces. I've got structured concurrency, which will give the same capabilities as the Rust borrow checker if you adjust your coding style. And all this in portable C11.
You can do this all in C but it is an absolute nightmare. Every large C program grows some strange bespoke and incompatible versions of all that stuff at some point. And they're all a pain to use because none of it is idiomatic to the language. It's seriously awful. Things like the Linux kernel are the worst offenders. I will be happy when the C language finally reaches the end of its miserable, slow, agonizing death.
And the clue was something you might not expect...
I programmed C++ for five years, and C for over ten years before that. I don't know rust, but I followed this discussion with great interest.
One of the topics that came up several times was being able to identify who wrote what C++ code based upon their choice of language subset without using blame.
In the pro-rust arguments and C++ counter-arguments and rust counter-counter-arguments and C++ counter-counter-counter arguments in discussions above yours, I was pleasantly surprised to see that grandfather comments were rarely (never?) the same author. At least the rust and C++ arguments were made by different people sharing some sort of group mentality.
Then I hit your thread and saw the grandchild comment: "I understand you think it's awful, but I do like it. Everyone has their preference." and I was like: "Okay. I bet grandparent is also ghoward."
The simple fact that no one is chiming in to grandchild your arguments is the point that you're missing. In fact, the entire subthreads you've spawned involve basically ghoward defending ghoward's position.
It's nice when other people can take over your work. That's what we're after.
I prefer to finish software. [1] I get it to where it needs to be and put it in maintenance mode.
I don't accept outside contributions. [2]
I prefer to work alone to keep the scope of my software manageable and to reduce communication overhead. And to avoid working with people. People are too complicated.
I obsessively document my software. [3]
I comment all of my code. I wrote design documents and requirements lists. I write documents about the source code, its concepts, and how to understand and read it. I turn my code into something that can be studied and used far into the future.
Most programmers are not like Donald Knuth. But there are a few that are. I'm one of them.
Please let me be like that. Don't make me work like everyone else because I can't; I've tried.
I'm fine if you all want to use Rust. I even said to use it by default in my first post.
You all seem unhappy that I do not want to use Rust. I don't get why.
I'm defending my position because it appears you all think it's not acceptable. You're wrong.
[1]: https://gavinhoward.com/2019/11/finishing-software/
[2]: https://git.yzena.com/Yzena/Yc#open-source-not-open-contribu...
[3]: https://git.yzena.com/gavin/bc/src/branch/master/manuals/dev...
I enjoy writing C (more than C++); I do not find it awful. If you cannot accept that, then there is nothing I can say to change your mind. What I don't understand is this atavistic obsession that "everyone must migrate to rust now", and "C is so dangerous in can explode in your hands while you are sleeping".
Please, go forth and multiply, and use rust to your heart's content. But be more open minded to the fact that there are people who like, enjoy or even love using C. As for me, I admit I have gone from interested in rust, to neutral, to an active dislike, because this narrow-mindedness some of its proponents show.
However, let's be serious, the anti-Rust crowd has not been some bastion of high-minded virtue with its flimsy arguments ("Just write better code..." and "Modern C++ doesn't have these issues..."), mole hill matters of taste ("Egads! The syntax!"), drive by hype hate, and unexplained red-herring cul de sacs ("I doesn't have a spec!" Okay, why do you need a spec?).
> I'm defending my position because it appears you all think it's not acceptable. You're wrong.
I'm not sure this and sentiments like it represent something less narrow-minded? Most of the time, it seems kinda resentful?
We are not. We just have different preferences.
You all have also implied that we are negligent for using C. I don't know about others, but I have not been.
That's why I have the challenge to break a release of my `bc`. I actually have not been negligent because I do put in the effort required to eliminate memory bugs as much as possible.
Until the RESF refrains from implying we are bad or negligent for not using Rust, we will be resentful.
I’m sorry that people have implied that, but I feel most of the time when Rust people say languages like C should be retired or deprecated, are doing so because your skill and attention to detail does not scale.
Maybe you personally have advanced enough to write safe code, and you have the requisite skills and insight to avoid any and all memory bugs, such that your C code is just as safe as what Rust would compile. That’s great.
But there’s always someone starting out and they will not have your skills. They will make the use after free, null pointer deference, buffer overflows, and other issues that the C language not only allow but encourage.
So the question is: how long do we tolerate new programmers making these mistakes in production code, leading to bugs and exploits for all, when other languages are readily available that would have caught those mistakes before reaching production? C was released 50 years ago, and in the intervening time a lot has been learned about how to write programs, and what language features are desirable in enforcing those practices. We also learned that when practiced aren’t enforced, they aren’t followed. So “just write modern c++”, which is espoused throughout this thread, doesn’t work to make c++ code safer, because it’s not enforced. Not taking advantage of those lessons learned seems like folly, irrespective of how bug-free your particular C codebase is.
This is a fair argument.
On the other hand, I wish we had less software so that attention to detail did not need to scale.
For example, I run a Gentoo machine with the Awesome Window Manager and no systemd. The end result is less than 50 processes running after I login.
My machine is powerful, but if I were running Gnome, it would still feel laggy. With this minimal setup, my machine is snappy even when running an update and compiling Rust, Chrome, Firefox, or anything else. (I did have to make my update script renice Portage to the lowest priority to make that happen, but it works.)
Nevertheless, it is good when less attention to detail is needed.
I'm making my own C replacement, and I'm going to rewrite my current project in it when it's done. It will be about as safe as Rust, if not safer because it will not have async/await.
> Maybe you personally have advanced enough to write safe code, and you have the requisite skills and insight to avoid any and all memory bugs, such that your C code is just as safe as what Rust would compile. That’s great.
Thank you.
> But there’s always someone starting out and they will not have your skills. They will make the use after free, null pointer deference, buffer overflows, and other issues that the C language not only allow but encourage.
Yes, they will. But I view this argument as equivalent to "roll your own crypto."
If no one actually rolls their own crypto, then we as an industry will lose the ability to do so, even when we need to. If nobody uses C, then we as an industry will lose the ability to do so, even when we need to.
When I started writing `bc`, I sucked at C. `bc` was so full of security holes.
So what I did was spend enormous amounts of time on the test suite and asserts and then hooked those up with sanitizers and Valgrind. Patterns of bugs repeated over and over.
But I eventually got to a point where I started to get good. I didn't release a 1.0 before that point; I waited until I was good and had done thorough checks with as many tools as I could learn.
I'm currently learning and implementing crypto. I am following the same process, except that I'll add in professional code audits by actual cryptographers, which I have to pass before I release the code.
I'm doing this because someone has to.
> So the question is: how long do we tolerate new programmers making these mistakes in production code, leading to bugs and exploits for all, when other languages are readily available that would have caught those mistakes before reaching production?
We should not tolerate this in production code, but this is a failure of the industry. Why are beginners writing production code in the first place?
This industry grew too fast for its own good. It would have been better if it had had a master and apprentice model. The best programmers would be "masters" (in the sense of master and apprentice), and juniors would be apprentices who would write code under the master until the master thought them good enough to be journeymen (moving up from junior), and over time, such journeymen would themselves come to be recognized as masters, and the cycle would repeat.
If the industry does not do that, we may soon lose the ability to do things we need to do.
(Funnily enough, this is another argument for less software because there will be less people to write production software, and they'll all be good at it.)
> C was released 50 years ago, and in the intervening time a lot has been learned about how to write programs, and what language features are desirable in enforcing those practices. We also learned that when practiced aren’t enforced, they aren’t followed. So “just write modern c++”, which is espoused throughout this thread, doesn’t work to make c++ code safer, because it’s not enforced. Not taking advantage of those lessons learned seems like folly, irrespective of how bug-free your particular C codebase is.
Surprisingly, I agree with you that it's folly. I really do. In my original post, I ended it by saying
> But seriously, use Rust if it's available for your target platforms, and you have no other preference.
People really should do that, even though I don't like Rust.
All I was doing was just to remind everyone that there is a time and a place for C.
By the way, the reason I don't use Rust is because I'm pretty sure I would actually write buggier code in Rust than in C. The reason for this is async/await: I just can't get it. I mean, I do get it, but the rules seem too complicated for my brain to do as safely as I can do threads and locks.
I think I am one of those people for whom async/await is dangerous, just like there are those that just can't get Lisp or Haskell.
I say this so people know I'm not some great programmer; I have my weaknesses like everybody else.
So it would be folly for me personally to write Rust.
At the same time, yes, it is folly to write anything but Rust if it works for you.
I 1,000% agree with this perspective. I also actually suspect that some form of professional licensing and/or personal liability would benefit the industry greatly, in that it would give more power to engineers to decline to build software irresponsibly due to pressure from management. Obviously this would be wildly complicated and there would be (potentially intolerable) downsides, but I do wonder what things would look like if we could revoke the licenses of people who repeatedly exercise poor judgment, or if responsible engineers knew they had the backing of a professional organization when pushing back against management.
The irony isn't lost on me that elsewhere in this thread I said that nobody is coming after your software engineering license if you keep writing C :) And I do realize that would probably be a disastrous idea in practice. But in my mind it's great.
And while I do agree that the industry grew too fast for its own good, this is unfortunately the reality we live in. The need for software has exceeded both our ability to produce it reliably and our capacity for training qualified engineers. So we have countless junior developers writing production code without good mentors. And worse, I think we also have a terrifying number of "senior" engineers who are actually junior engineers with a lot of experience but trapped in a local maximum. I don't know how we fix this.
> By the way, the reason I don't use Rust is because I'm pretty sure I would actually write buggier code in Rust than in C. The reason for this is async/await: I just can't get it. I mean, I do get it, but the rules seem too complicated for my brain to do as safely as I can do threads and locks.
I "get" async/await but I… hate that it has to exist. I avoid it in all of my Rust projects. Partly because I don't want to use it, but also because I've never needed to solve a problem in a domain where it would have been invaluable. So just so you know, I've been writing Rust since right around 1.0 and I've been essentially able to just pretend it doesn't exist. I've never used it, but also I've never had to think about not using it if that makes sense.
I also 1,000% agree with this. In fact, if there is any activism I do within the industry, it's pushing for this.
> Obviously this would be wildly complicated and there would be (potentially intolerable) downsides, but I do wonder what things would look like if we could revoke the licenses of people who repeatedly exercise poor judgment, or if responsible engineers knew they had the backing of a professional organization when pushing back against management.
I don't think there would be any downside other than expensive software. But studies have shown that poor software is more expensive!
The one thing that would complicate it is Open Source, but I think that hobbyists should be allowed to practice and put code up with no vetting, just like an engineer might design a shed for his backyard and post it on a blog without his/her seal of approval.
However, if some company decides to use that shed/Open Source code in a project, that company's certified engineers/programmers should be required to vet it the same as they would do for their own code.
And as for the gatekeeping of certification, I think uncertified programmers should be allowed to program, but under the supervision of a certified programmer who accepts liability for their work because that chief programmer should be checking their work.
> The irony isn't lost on me that elsewhere in this thread I said that nobody is coming after your software engineering license if you keep writing C :)
Maybe a litte irony, but I would probably be harsher on myself than you would think.
I think there would probably be a certification for writing C, one for writing Rust, etc.
So I would not be allowed to program as a certified engineer for Rust, but I could probably be certified in C, even though the certification and standard of care for C would be much harder and have a higher bar, for obvious reasons.
I don't know what the industry would set the standard of care for C at, but I personally wouldn't set it lower than my personal standards. If it was set at that, then my license should not be taken away, even if I were paid to work on `bc`.
But if it was set higher, say at the level given to libcurl or SQLite, then yes, I should lose my license if I were working for pay on `bc`, unless I stepped up.
In addition, if I worked on `bc` for pay, my failure to prevent memory bugs in `bcl` recently (the one where Valgrind was not hooked into its tests properly) should, at the very least, put me in front of a licensure board to explain myself. My recent failure to prevent the double-free on `SIGINT` when running expressions should also put me in front of a licensure board to explain myself.
If any paying user had been caused trouble for those bugs (no one ran into them as far as I know), I should have to compensate them for the trouble and probably lose my license for negligence. I was extremely upset that I let those slip through.
So no, I shouldn't lose my license for using C, but there should be one for C, and I should have at least come close to losing it for the recent mistakes that I would consider near-negligence.
> And I do realize that would probably be a disastrous idea in practice. But in my mind it's great.
I want to hear why it might be a disastrous idea. I can't see how it would be because it would lead to less but better quality software, and if bad software actually costs more in the long run, it would actually save the industry money! So I fail to see how it would be disastrous.
Please enlighten me on this; I have to know the weaknesses.
> And while I do agree that the industry grew too fast for its own good, this is unfortunately the reality we live in. The need for software has exceeded both our ability to produce it reliably and our capacity for training qualified engineers. So we have countless junior developers writing production code without good mentors.
Yes, this is the reality. This is why I don't dismiss Rust even though I hate it.
> And worse, I think we also have a terrifying number of "senior" engineers who are actually junior engineers with a lot of experience but trapped in a local maximum.
I really don't want you to be right, but I think you are, and that terrifies me because something bad is going to happen. I don't know how we fix this.
However, the end result of that bad thing might actually be certification and standard of care, which wouldn't be a bad thing.
As they say, regulations are written in blood, and I think that's the only way to fix this.
It's just too bad that people will have to die before that happens. I mean, I thought the Boeing 737 MAX would be the wake-up call, but it wasn't. Sigh...
> I "get" async/await but I… hate that it has to exist. I avoid it in all of my Rust projects. Partly because I don't want to use it, but also because I've never needed to solve a problem in a domain where it would have been invaluable. So just so you know, I've been writing Rust since right around 1.0 and I've been essentially able to just pretend it doesn't exist. I've never used it, but also I've never had to think about not using it if that makes sense.
That makes a lot of sense, and I don't blame you.
It's too bad we had a misunderstanding at the beginning of our conversations about this because I think we would agree more than disagree on the direction the industry would go. Oh well; we got to a point where we cleared up the misunderstanding.
Thank you.
My answer to this is probably too large for a reply here, but TL;DR is that software engineering is an enormous, complex field. I do know that there are far more ways to do something like this wrong than there are ways to do it right, but I have no idea what would be the right way. Language-based licensing makes sense, but so does licensing for sub-fields like security-related areas (handling PII, cryptography, even different areas of cryptography), operating systems (Windows, macOS, Linux, *BSD, et al), and large frameworks (Hibernate, Rails, React, etc.). But I imagine in practice things would get real murky real quick.
And it's also something where it could easily become too onerous and impossible to develop software.
Nobody is saying this!
In the original tweet, Mark Russinovich said he thinks C and C++ should be deprecated. I believe if you asked him to elaborate on this, he would say he believes we should stop using them when possible. Not "must". "Should". And further, I suspect he'd clarify that he is imploring this of the industry as a whole, and not at the scale of individual developers.
People still write asm, and nobody is coming for their heads. We need people like that! And we will need people who are skilled in C for the far foreseeable future. But the time has come where there exist alternatives to C and C++ which are superior for a very large bulk of their remaining use-cases. He's not scolding individual engineers who choose to continue writing code in a language he enjoys. He's calling for the industry as a whole to recognize this new reality and move forward with the times.
First off is the code in [1]. It's technically under several licenses, but I can give it to you under the public domain because bounds checking in C is important enough that I'll give it away.
The `y_ARRAY_TYPE()` macro generates a struct that is an array with bounds. Use it like this:
typedef y_ARRAY_TYPE(uint32_t) uint32_t_arr;
`uint32_t_arr` is a bounded array of `uint32_t`'s.You can then pass that array to functions and do bounds checks with the `y_i()` macro (for when the struct value is not a pointer) and the `y_ip()` macro (for when the struct value is a pointer).
To implement RAII, the code to do that is in the same repo, but it's...much more complicated: a full stack allocator. I just add the destructor as a parameter when allocating memory, and when the allocation is freed, the destructor is called when it's non-NULL. Then there are functions to allocate and free, but it is always done in a stack, to emulate the real stack.
By the way, the type of destructor is
void (*y_Destructor)(void*)
and it takes a pointer to the item to be destroyed.Structured concurrency takes the idea of a thread-local stack and sort of generalizes it across threads. The idea is that each thread has a parent, and that parent is not joined until all of its child threads are joined. All threads form a tree, almost exactly like process trees in Linux.
This means that if you want to have another thread borrow an item, you just have to make sure that thread is a descendant of the thread it is borrowing the item from, and you have a guarantee that the item will never go out of scope before the borrowing thread does.
Sometimes you need to change your code to do that. You can "push" things "down the stack" by passing function pointer callbacks to callees who then create the item to borrow and call the callbacks. Inside the callbacks, the borrowed item will always exist.
There's more to it than that (you can turn a thread tree into a DAG [2], allowing you to turn threads that are not descendants of a thread into descendants), but that's probably good enough to start you off.
[1]: https://git.yzena.com/Yzena/Yc/src/commit/cf4c96b3560d/inclu...
[2]: https://lobste.rs/s/8msejg/notes_on_structured_concurrency_g...
The fact that I have built all of this is part of why I don't accept contributions. [1] I don't expect people to be able to read my code.
[1]: https://git.yzena.com/Yzena/Yc#open-source-not-open-contribu...
This could also be done with a macro:
#define y_d(p) ((p) == NULL ? abort(), *p : *p)
Otherwise, the compiler (clang, usually) warns me when a NULL pointer is passed in and I have asserts to catch them.Even before I had all of this infrastructure, deferencing NULL pointers was not a problem for me personally; it's just one of the mistakes I tend to not make. So that's why I don't have a macro for it.
For use-after-free, I use scopes. My stack allocator has a function that will mark the start of a scope, and I call it when entering a new scope. Then the pointers that are allocated during that scope will all be freed when I call the function to free every item in the scope, but those pointers will also go out of scope, which means the compiler won't let me access them.
It looks like this:
void
func(size_t s)
{
y_stackallocator* p = y_strucon_stackallocator();
// Random code.
// Open a new scope. Notice that the scope is a bare scope.
// But it could also be an if statement or a loop.
{
size_t* sp = y_stackallocator_malloc(p, sizeof(size_t) * s, NULL);
// Random code.
// This frees everything in the scope, including sp.
y_stackallocator_scopeExit(p);
}
// Scope has exited; sp is not accessible, no use-after-free.
}
This is less rigorous than Rust, but I use the principles in Joel's "Making Wrong Code Look Wrong" [1] here. If I have scopes that don't look like the above, they are wrong.[1]: https://www.joelonsoftware.com/2005/05/11/making-wrong-code-...
But I do use them, and I also use sanitizers against large and thorough test suites, with excessive fuzzing thrown in for good measure. And I mix all of that with crash-happy code littered with gobs of `assert()` calls that document as many of my assumptions as I can find.
Those help me find about all I can find.
But I'm still writing a language that is as safe as Rust that I will auto-translate my code into when it's done.
By the way, I'm not using Rust because I don't like it. That doesn't mean it's not good, but I really hate async/await, along with a few other Rust design decisions.
I'm kind of picky as a programmer.
Yes, C fails against Rust here, but that's why I put in the extra effort to bring it up to the same level regardless.
Just curious, how do you intend to make it memory safe? By using a garbage collector, automatic reference counting, a borrow checker, or something else?
tl;dr: If threads never exit before their descendants, and you only borrow an item in callees and in descendant threads, that would negate the need for a borrow a checker.
As for sharing an item across threads and still not having data races, this will be done by implementing something close to Rust's Send/Sync.
There will be ARC implemented by RAII, just like Rust.
Basically, the language will be built around structured concurrency, including the standard library.
Does that answer your question?
So do you also intend to completely disallow mutation? Because that's the only way I could see this matching Rust's safety guarantees without actually having a borrow checker.
Say, for example, that you allocate a new string, and you take a reference to it, and then you append to that string within the same scope. This triggers a reallocation which will make that reference invalid. To make that safe you'd either need to have a borrow checker (to be able to detect at compile time that the reference was invalidated), or you'd have to disallow mutation (the act of mutating wouldn't actually mutate that string, but create a new one, leaving the old one alone until it goes out of scope).
In my language, there are strings, which are fixed size and cannot be reallocated, and string builders, which hide the actual string behind another layer of indirection to avoid the problem with mutation.
That sort of pattern would be used as necessary to avoid the problems with mutation in the same thread. And Send/Sync would take care of the rest across threads.
I still have a lot of technical debt with that, but I haven't gotten to it. However, when I do change it, I'll be able to find all instances automatically with grep.
Change MyType to RAIIMyType or similar in the function to get the checking when using GCC/clang with asserts enabled. In practice sometimes types should drop out of scope without deallocation - return from functions etc. Thinking about it now I should probably apply it by default and use (MyType) to avoid the macro expansion selectively.
You need the test suite to verify that your code does what you think it does anyways, the sanitizers are just a nice bonus to verify that it also has the safety you think it does.
The test suite and asserts for every assumption are hugely important too. Testing under runtime is important.
No. This is only true if you don't care about occasional bugs. e.g. hobby projects. But if you're talking about mission-critical or security-critical software, there is a gap - or a canyon - between C vs C++ vs Rust. And no amount of extra "efforts" by the programmer's part can bridge those gaps completely.
The code is my `bc`. [1]
Find a memory bug, any memory bug, in my `bc` after 1.0.
Rust has occasional memory bugs too; I mentioned that specifically. It still happens.
So if you really are correct, break my `bc`.
I know how to call `strcpy` safely. Are we clear to put that back into the Linux kernel then?
I'm only claiming that I personally can do just as well in C as I could do in Rust, and that I prefer to work in C, so I might as well.
Break my `bc`.
I'm surprised by this confidence given one of the commits on the first page is "Fix a double-free when using expressions and sending SIGINT". And going through the commit history quickly reveals "Fix memory bugs in bcl" (a value not being initialized) and "Fix memory leaks in bcl" (missing dealloc), all within the last two months and all which are trivially not a problem in Rust.
Yes, there will be memory bugs during development, but I usually find them before release. There will definitely be commits fixing memory bugs during development.
The bcl library is an exceptional case, where my test suite did not have sanitizers and Valgrind properly hooked up, and that one was because it went from a global (guaranteed to be zeroed) to allocated.
But I also said to find one in the program, not the library.
I issue that challenge again: find a memory bug in the `bc` or `dc` program in a release after 1.0.
Oh, and the double-free with `SIGINT`? Rust isn't going to help you much there. Signals are not part of Rust's model.
You did not say anything of the sort.
>But I also said to find one in the program, not the library.
You did not say anything of the sort.
You said:
>>The code is my `bc`. [1]
>>Find a memory bug, any memory bug, in my `bc` after 1.0.
>>[1]: https://git.yzena.com/gavin/bc
But okay, let's acknowledge the moved goalposts.
>I issue that challenge again: find a memory bug in the `bc` or `dc` program in a release after 1.0.
Tell me what subset of the repo named "bc" you consider to be "the program"
>Oh, and the double-free with `SIGINT`? Rust isn't going to help you much there. Signals are not part of Rust's model.
Crates like tokio::signal allow a signal to be converted to a stream of events, which can be handled along with any other events in the program, instead of interrupting the current fn in the middle and necessitating longjmp shenanigans. Since the existing stack is not interrupted in any special way, dtors fire as they're supposed to.
Clearly, the parts where you aren't able to find memory bugs.
Anything built without the -a option to configure.sh is "the program." That's the vast majority. You can try the library too, but there is that one mistake you already know about. I don't think there are any others though.
And again, even with the things you all have found that are in random commits, it doesn't really matter; Rust isn't completely memory safe either. It's close, but not quite.
tokio::signal-type code would not work for `bc` signals.
`bc` is a special program; most programs are I/O-bound, but `bc` is both I/O- and CPU-bound. And it's interactive, so it's got to respond to the user as fast as possible.
It's quite possible for a user to enter an expression, not realizing how expensive it is to compute (since `bc`'s numbers can be arbitrarily large). In that case, a `SIGINT` should be responded to instantly.
Turning signals into an event stream to read would not do that because the signal handler literally has to `longjmp()` out of itself.
It won't `longjmp()` out if it's not safe to do so, but it can be safe to do so. And when it is not safe to do so, it will set a flag and return normally.
Then the code that wasn't safe to jump around finishes, it will check the flag and jump itself once it is safe.
This is what keeps my `bc` responsive even if you have a long-running computation.
To see this, compile and run my `bc`, and give it this input:
>>> 2^2^32
It will hang because it's calculating a LARGE number.Press Ctrl+C. It will instantly return to the input prompt.
I might be wrong that tokio::signal cannot do that, and if so, I apologize. But it doesn't appear so from your description.
Also, I have the same sort of code in my new project to turn signals into an event stream in C.
I'm almost tempted to believe this entire exchange was an elaborate setup to convince people to use memory-safe languages.
[1] except I'm… pretty sure it would have been
Just try it. Break my `bc` in a release. I dare you. Until any of you do, you're just trolls or the RESF.
Nobody is hiding around the corner waiting to take `gcc` or `clang` away from you if you want to keep using them. Nobody's threatening to take away your software engineering license if we catch you writing a memory bug.
This whole thread is ridiculous. “The safety improvements in modern cars are substantial. If you're buying a new car these days, you should probably buy one made after 2018.” “Well I'm still driving my 1969 Malibu. Plus I’ve never been in an accident so I don’t need those safety features.” “Okay but… what are those dents in your car?” “I said no accidents on public roads. Prove me wrong or STFU.”
To refute all of that, I point people at some code that they would probably struggle to break.
Many of us think there are better alternatives. We're excited about these better alternatives. We want people to use these better alternatives. We think these better alternative solve a lot of problems that many people spend a lot of time dealing with. We think these better alternatives prevent many of the types of bugs that regularly ruin people's afternoons, evenings, and weekends. We really think you should try it out, but if you don't like it, literally nobody is coming to take your compiler away from you.
We do think a lot of the common arguments against moving to these languages are bullshit though. "Rust can't do self-referential data structures" is one of them. "I have a ton of expertise in C and it would take more time than I'm willing to spend to get to that level in something else", "this project is already written in C and mature", and "I write code for unsupported platforms" aren't bullshit, but they are ones that naturally decay in how compelling they are over time.
And as much as I believe you personally can write memory-safe programs in C, I would be willing to bet this guarantee would go out the window the moment you add a second maintainer who can push and release code without you vetting every commit.
I've had people say all of these things to me in various ways.
"You should be ashamed of yourself," is a typical phrase used.
> Many of us think there are better alternatives. We're excited about these better alternatives. We want people to use these better alternatives. We think these better alternative solve a lot of problems that many people spend a lot of time dealing with. We think these better alternatives prevent many of the types of bugs that regularly ruin people's afternoons, evenings, and weekends.
This excitement has been over-the-top and as mentioned by one or more people in this thread, it has actually driven people away from Rust. As much as I don't like Rust, I don't want that to happen.
> We really think you should try it out, but if you don't like it, literally nobody is coming to take your compiler away from you.
When people say they want to deprecate C, that's what they mean. If you deprecate C, the compilers will be abandoned, which in the software world converges to the same effect as taking it away because compilers need ongoing maintenance to keep up with new platforms and such.
If a new platform becomes mainstream, and there's no C compiler for it, then my C compiler has effectively been taken away.
This is one reason I'm making my C replacement language: I do think that C will eventually be abandoned on the major platforms, and I want to have switched by that time.
> We do think a lot of the common arguments against moving to these languages are bull** though.
Which is fair. You didn't say all of them are, and yes, a lot of the common arguments are crud.
> "Rust can't do self-referential data structures" is one of them.
I actually agree with you; this is a crud argument. In order to make my C as safe as possible, I don't use self-referential data structures either; I use a parent data structure.
I did this with linked lists [1]. The linked list is a parent data structure that owns everything, and the items in the linked list just have indices to their neighbors. This allows me to tie Rust-like lifetimes to the items.
And any self-referential data structure can be expressed in terms of a parent data structure and children data structures.
So yes, you are right: this argument is crud.
> "I have a ton of expertise in C and it would take more time than I'm willing to spend to get to that level in something else", "this project is already written in C and mature", and "I write code for unsupported platforms" aren't bull**, but they are ones that naturally decay in how compelling they are over time.
I agree. This is another reason I'm still writing a C replacement for myself.
> And as much as I believe you personally can write memory-safe programs in C, I would be willing to bet this guarantee would go out the window the moment you add a second maintainer who can push and release code without you vetting every commit.
Yep. I agree. Even if it's Linus Torvalds, Ken Thompson, or anyone.
I still vet every commit, or just not accept anything.
It also helps me keep the scope manageable: if I can't do it myself, the scope is too large.
[1]: https://git.yzena.com/Yzena/Yc/src/branch/master/src/contain...
I'm trying very hard to not "no true scotsman" myself here. But I tend to think of it like this: there's people, and then there's Twitter personas. There's a lot of very strong, absurd opinions that Twitter personas have but that I don't ever seem to encounter in the real world.
Maybe another way of putting it is that if I dropped you on stage in the middle of a RustConf keynote, nobody would actually have these types of opinions. And if anyone did express such a thing, there would be overwhelming opposition to it. But of course I can't prove this, and I'd be willing to admit I'm wrong. And none of this discounts the fact that you've apparently seen these types of opinions firsthand.
> > We really think you should try it out, but if you don't like it, literally nobody is coming to take your compiler away from you.
> When people say they want to deprecate C, that's what they mean.
I don't think that's a reasonable take at all. I'd be willing to bet that what Mark Russinovich was saying was exactly what you just stated in another thread: "I agree with this. I never said people should use C by default; absolutely not. They should use Rust by default."
> If a new platform becomes mainstream, and there's no C compiler for it, then my C compiler has effectively been taken away.
Being taken away is very, very different from other people not being sufficiently motivated to build something you want to exist. Nobody has "taken away" COBOL from folks by not porting compilers to arm64 (I have no idea if arm64 COBOL compilers exist, feel free to substitute a suitable arch/lang).
> This is one reason I'm making my C replacement language: I do think that C will eventually be abandoned on the major platforms, and I want to have switched by that time.
I'd be willing to bet substantial sums of money that "eventually" will not include either of our lifetimes. And my guess is it would be far less work to port C to (or write an LLVM backend for) x86-128 or aarch256 or RISC IX than to maintain your own language and keep it running on all the major platforms. But good luck to you nonetheless.
> Yep. I agree. Even if it's Linus Torvalds, Ken Thompson, or anyone.
I'm pleased you pointed this out! I'd debated saying this but opted not to, it's great that we agree on that extra detail.
If we expand that to Reddit and Hacker News, I have to agree, so it might have just been personas I went up against.
> Maybe another way of putting it is that if I dropped you on stage in the middle of a RustConf keynote, nobody would actually have these types of opinions. And if anyone did express such a thing, there would be overwhelming opposition to it. But of course I can't prove this, and I'd be willing to admit I'm wrong.
But I've never been to RustConf, so I can't dispute this. I'll simply have to trust you on this one.
Though dropping me of all people into a RustConf keynote would be a wild prank. Hilarious.
> And none of this discounts the fact that you've apparently seen these types of opinions firsthand.
Unless I've only seen personas, as you suspect, and I can't refute that.
> I don't think that's a reasonable take at all. I'd be willing to bet that what Mark Russinovich was saying was exactly what you just stated in another thread: "I agree with this. I never said people should use C by default; absolutely not. They should use Rust by default."
I'm not so sure because I used to be one of the people that thought C should die, as in, have everything rewritten into another language. People like that do exist.
But again, they may just be personas. Whoops.
> Being taken away is very, very different from other people not being sufficiently motivated to build something you want to exist. Nobody has "taken away" COBOL from folks by not porting compilers to arm64 (I have no idea if arm64 COBOL compilers exist, feel free to substitute a suitable arch/lang).
This is a fair counterargument. I guess I should correct myself by saying that it would feel like my C compiler would be taken away.
> I'd be willing to bet substantial sums of money that "eventually" will not include either of our lifetimes.
I'm not so sure, but no one can predict the future. :) I wouldn't have thought Rust would end up in the Linux kernel when I first heard of it. Now it's all but certain to happen.
> And my guess is it would be far less work to port C to (or write an LLVM backend for) x86-128 or aarch256 or RISC IX than to maintain your own language and keep it running on all the major platforms. But good luck to you nonetheless.
That's true. It's why my language will bootstrap itself to C99! For every platform that is too much work to support directly, I'll support it by having a C99 compiler for that platform.
C99 should not need much maintenance. I hope. Or someone else will care enough to do it. I hope.
> I'm pleased you pointed this out! I'd debated saying this but opted not to, it's great that we agree on that extra detail.
Good! And you're welcome.
Yeah, I'm picky. I've rewritten code given to me by a FreeBSD kernel developer who is twice my age and much better than me.
"Twitter personas" is just my pet name for the phenomenon because it seems strongest (or maybe I just first noticed it) there.
> But I've never been to RustConf, so I can't dispute this. I'll simply have to trust you on this one.
Hah! I've never actually been either. I just meant this as a standin for putting you in front of actual, real, physical people who also are likely closer to the evangelist end of the spectrum.
I did find at least one case where a function in isolation is explicitly not memory-safe, but its safety depends on implicit and undocumented assumptions about how it's called. I didn't find a way to exploit it from the userland program. In `bc_parse_addNum`[1], a `char *` string is indexed into without checking the length. Callers are expected to provide strings of at least length 2. That expectation is not documented, though it is adhered to. But it is a landmine waiting to be tripped over should that assumption change.
But this is a sideshow. Experts have been insisting for decades that they can write crash-free C and yet we continue to regularly find exploitable memory issues in every large multi-author C project. It's plain as day that—for almost all of us—an increasingly indefensible amount of the time spent on C programs is in dealing with the types of bugs that languages like Rust prevent outright. Whether that's simply finding and fixing them, architecting programs to avoid them, incorporating those fixes into downstream projects, mitigating their impact in live production systems, or whatever, our industry pays an enormous ongoing cost. Even in projects that have never had a public release with a memory bug, significant engineering time is spent on them just during development iteration.
As a handy example, the Linux kernel is still trying to rid itself of `strlcpy`[2] which has been the source of multiple CVEs. This process has taken upwards of twenty years. And that's after spending god knows how much time and effort migrating to `strlcpy` from `strcpy` in the first place.
[1] https://git.yzena.com/gavin/bc/src/branch/master/src/parse.c...
This is a nice compliment, thank you.
> Except when his sanitizer setup is accidentally disabled, of course.
Fair criticism. XD
> I did find at least one case where a function in isolation is explicitly not memory-safe, but its safety depends on implicit and undocumented assumptions about how it's called. I didn't find a way to exploit it from the userland program. In `bc_parse_addNum`[1], a `char` pointer string is indexed into without checking the length. Callers are expected to provide strings of at least length 2. That expectation is not documented, though it is adhered to. But it is a landmine waiting to be tripped over should that assumption change.
Callers are actually required to pass a string of length 1 including the nul terminator, but you are correct, this assumption is not documented in `bc_parse_addNum()`, and it should be.
By the way, `bc_parse_zero` and bc_parse_one` are constants, so I can make assumptions about them. This is why an empty string is fine: those constants do not have nul terminators at index 0, so if the string parameter does, the short-circuit operators will short-circuit.
I've pushed commit e4b31620f181 to document that assumption, along with a note that assuming a non-empty string might be useful too.
> But this is a sideshow. Experts have been insisting for decades that they can write crash-free C and yet we continue to regularly find exploitable memory issues in every large multi-author C project. It's plain as day that—for almost all of us—an increasingly indefensible amount of the time spent on C programs is in dealing with the types of bugs that languages like Rust prevent outright. Whether that's simply finding and fixing them, architecting programs to avoid them, incorporating those fixes into downstream projects, mitigating their impact in live production systems, or whatever, our industry pays an enormous ongoing cost. Even in projects that have never had a public release with a memory bug, significant engineering time is spent on them just during development iteration.
I agree with this. I never said people should use C by default; absolutely not. They should use Rust by default.
But as I said in another of my comments [1], I think I personally would write buggier code in Rust than in C.
Nice!
> By the way, `bc_parse_zero` and bc_parse_one` are constants, so I can make assumptions about them. This is why an empty string is fine: those constants do not have nul terminators at index 0, so if the string parameter does, the short-circuit operators will short-circuit.
Ah, of course. I knew that they were constants, but I didn't consider the short-circuiting of the comparison before indexing further into the string.
> But as I said in another of my comments [1], I think I personally would write buggier code in Rust than in C.
I hope you understand that—all snark aside—I truly, genuinely believe you. I do suspect that if you had invested the just time you've spent figuring out how to work around C's memory-safety shortcomings, your proficiency would be within spitting distance. But obviously those costs are already sunk. And at the end of the day, if you just love C and only want to write C then it doesn't matter what sorts of things another language provides.
I love C, but I've also come to love Rust. Sum types and exhaustive pattern matching are the sorts of things that are hard to live without once you've had them, and now languages that don't offer them are pretty much ruined for me. But at the same time I'm not a fan of the async/await paradigm, though I begrudgingly understand why it was necessary and why it was designed the way it was. For now I simply avoid it, but it makes me sad that we were never able to find something better.
No worries! That's why I specifically wrote it that way instead of a `strcmp()` call. I may be a little obsessive over getting my code right.
> I hope you understand that—all snark aside—I truly, genuinely believe you.
Thank you.
> I do suspect that if you had invested the just time you've spent figuring out how to work around C's memory-safety shortcomings, your proficiency would be within spitting distance. But obviously those costs are already sunk.
I actually don't know. It's possible, even plausible, that you are correct.
But I've spent gobs of time trying to understand async/await and failed. It wasn't as much time as I spent honing my C, but it was a lot. And I did not seem to make progress.
However, I might have been making progress and didn't realize it. Or maybe an epiphany like the one I experienced with Haskell would have been in the future.
Or maybe my brain just doesn't work in a compatible way with async models. I don't know.
It is one of my regrets that I did not try harder. Oh well; I guess I loved the visible progress of fewer and fewer crashes in a fuzzer more, even if it was slower.
> And at the end of the day, if you just love C and only want to write C then it doesn't matter what sorts of things another language provides.
As long as I am not negligent! I'll add more about this in a reply to another of your comments, though.
> I love C, but I've also come to love Rust. Sum types and exhaustive pattern matching are the sorts of things that are hard to live without once you've had them, and now languages that don't offer them are pretty much ruined for me.
I agree. I love them too, so much so that I run clang with -Weverything to get exhaustive matching in switch statements. And I emulate sum types with enums and unions. I always use switch statements to match on the enum value, which sort of gives me the experience of Rust sum types and exhaustive pattern matching. Sort of.
My language will have them for sure.
> But at the same time I'm not a fan of the async/await paradigm, though I begrudgingly understand why it was necessary and why it was designed the way it was. For now I simply avoid it, but it makes me sad that we were never able to find something better.
I agree. I'm sad about it too. I couldn't really reject Rust if it didn't have async/await, and I wish I didn't have to reject Rust.
(Though the RESF is still off-putting.)
I'm hoping that my language will be a competitor to Rust but allow people to try structured concurrency instead. If Rust still "wins," that's fine; people want async/await. But if they coexist or my language "wins," that's good too.
Eh, sorry for the long-winded comments.
I've said this elsewhere but as a long-time Rust user I have literally never used or even encountered async/await. It exists, and I could use it if I needed to, but I never have nor have I had to spend effort avoiding it or thinking about it. It as far as I can tell a feature you can essentially entirely forget exists.
Security critical is also rather meaningless, because the idea that a specific language must be used to write secure software is something that the Rust community is claiming but is otherwise unproven and not particularly popular as an opinion. In fact I’ve seen many counters that nearly any GC language offers the same security guarantees as Rust.
Finally, there’s the mighty inconvenient fact that a large amount of safety-critical software (a well-defined term and domain!) is written in C and C++ with a track record of multiple decades while Rust is completely unproven.
Well stated.
You can even justify using malbolge for your hobby project with "I like it" or "It's just for fun".
If your company is only going to pay you for producing malbolge code, then you write malbolge or quit. If you decide to stay, then trying to change their mind might be a good idea if you can spare the effort.
They should hold, but the RESF can be too absolutist. The wording of the tweet encouraged that, so I was just trying to push back on it.
The really tricky macro though comes when you want to check races in shared mutable state...
Instead, I use ThreadSanitizer and add locks where I may not even need them. Then I may remove some, or change them to different synchronization primitives, and between every change, run TSan several hundred of thousands of times to tease out any race conditions. It's my way of fuzzing for race conditions.
Mark, if you read this, please start with porting Sysmon to Rust. A Microsoft supported doc on how to use Rust when developing using the DDK would be amazing as well.
Sysmon on Linux uses ebpf, would be a selling point if it was also written in Rust.
- Static linking of everything
- Big dependency trees that somehow remind me of npm
- Slow compilation, it should reach at least the average speed of C compilation
- Big binaries because of static linking
Before this is solved, I frankly wouldn't even consider touching rust again for personal projects, did it once, and it was an awful experience with too long compile times, as my style of development depends on fast compile-run-test cycles and having to wait around a minute to recompile for a small program is just too much.
I believe other big companies have similar reservations about using C/C++ on new projects. And given the cost of cleaning up the security mess that using C/C++ has caused these companies, I can see where they are coming from.
It's not about demonizing people but just a simple, rational business decision to not use C/C++ for new things anymore. We have Rust now and it's capable of delivering the same level of performance as C/C++ but without all the memory leaks, buffer overflows and other costly headaches that a CTO of Azure needs to worry about messing up his business. Not worth it anymore.
People taking things like this personally is unfortunate but more a problem these people have than anything else. I get it, it's not fun having your favorite language - and by extension you - labelled obsolete. Not a nice message to receive.
Server side services (read outside of Unreal Engine Server) are not written in C++ however.
There is a difference between Mark Russinovich saying this, as a personal opinion, and Mark Russinovich, Azure CTO, saying this as a company policy/directive.
This tweet does not indicate that it's from him in his official capacity as Azure CTO.
Azure will inevitably use Rust more.
Also, RITF, I love Rust but remember zig exists so chill
I also want to say one thing-- sometimes it's not so easy to just decide to write a project and say okay let me write this in Rust. You have to see available ecosystem. I hate python because I'm a systems programmer at heart but damn sometimes all it takes is a pip install, import and 3 lines to get going and understanding things.
Rust ecosystem is hugely lacking. I don't want to spend time writing boilerplate FFI. I've heard zig is better in this regard
Inquiring minds want to know.
Rust Is The Fuck doesn't parse. Did he mean RITFS, i.e. "Rust Is The Fucking Shit"? He probably didn't mean RITFBAEL, i.e. "Rust Is The Fucking Shit".
What are we hiding here?
Rust has only one real compiler and no independent language standard.
Rust is also the only alternative that is really being discussed most places. For an idea as major as "deprecate C/C++" you really want a couple solid alternatives. Rust is not perfect for everything, and so its easy to pick on the weaknesses and say "that's why we're sticking with C/C++".
I guess Ada or D are viable alternatives, too, and maybe need more attention. But the tweet only mentions rust.
Standards only make sense to me in the presence of multiple compilers or formal verification. There is ongoing work on supporting the second use case. I don't understand why people want multiple compilers.
Most people don't. But most development moved away from C/C++ before rust.
If you want to call C & C++ "deprecated" you can't ignore the margins, which is exactly where those languages thrive.
Maybe there needs to be a tiny (incomplete?) rust compiler. Or maybe there should be an interpreter.
In which case the issue is "Rust doesn't have a small compiler" or "Rust doesn't have an interpreter". Having multiple compilers won't necessarily mean that those issues are resolved. A more generic argument would be something like "the existing compiler doesn't cover my use cases".
Typically this would be resolved with a language standard.
It seems like Rust is leaning towards doing that like it's done in python. One reference implementation, a language reference and a bunch of design documents (PEP, RFC). There are some areas where the language reference is lacking right now but that can be, and is being, fixed over time.
I never understood why it is a problem for some people. Single compiler means more people working on it instead of recreating same work multiple times (modules and coroutines are still not fully supported across all 3 biggest compilers).
Note to whoever I've angered: Please, don't reply with your reasoning why you need GCC. I don't care about your reasoning and that GCC unlike LLVM supports this platform that only used on calculators made by defunct company and sold whole 3 of them.
Yeah, most people doing scientific computing might use Python, but then you have whole groups of people who are used to something else and would plainly prefer not to use a language for completely personal reasons.
Like, hey maybe the syntax sucks.
I have definitely, for example, used Java in a project where I would rather walk on hot coals than add more Java to the world... Except the project was to write a second webserver that included all the accreted wisdom the company had built up over the years and we already had a first one written in Java.
The pain of adding more Java was offset by avoiding the pain of having to explain to a vice president how the company got hacked a second time in the exact same way we got hacked 5 years ago...
After all, isn't that why all the "safety over all" people are switching to Rust now rather than Ada 20 years ago?
But the cost of unsafety in C++ is often a vuln. This makes it a meaningfully different choice.
We have all sorts of regulation in other industries to protect consumers, and with so much of our economic infrastructure dependent on the security and integrity of information processing, it’s bizarre to me that we’re still using programming languages with severe deficiencies for these purposes.
Will there be performance hits, cost hits, and inefficiencies introduced by requiring safer languages? Of course. But I see that as vastly preferable to the dangerous state of cybersecurity at almost all companies.
wow that is an awful idea
Unsafe binary? Run it in docker.
Crashes? Run two and monit.
RAM leak? Restart with cron.
Now I'm not saying that these are good solutions, but they are good enough so that plenty of companies get away just fine with running buggy c++ software in production. So in my opinion, the biggest improvements come from better abstractions and good libraries. And c++ still has the lead there.
Sounds pretty hyperbolic to me.
https://arstechnica.com/information-technology/2022/09/new-l...
use this picture in a hexeditor:
https://cdn.arstechnica.net/wp-content/uploads/2022/09/shiki...
The "C/C++ Users Journal" was a very popular publication and no one took issue with its name. Nor do people take issue with Dr. Dobbs which has a "C/C++" section with articles from highly influential members of the C/C++ community.
C++ is a complex language, so people invent ways to show how dedicated they are to it, and nowadays that means pretending to get all worked up over the term "C/C++".
You come up with examples that are over 30 years old.
You wish it was recent and something you could pretend about. But anytime you write it, you are telling a lie. Being seen lying tells the reader more about you than you probably intend.
If by recent you mean well over 20 years ago. When I began learning C circa 2000, I used to hang out on comp.lang.c, and "C/C++" was very much frowned upon. And for good reason--people felt entitled to ask C++ questions in a C newsgroup, which was and remains a poor idea. Even if they were asking questions relevant to both, e.g. regarding pointers, it's still a much better idea to ask in a C++ newsgroup. See https://en.wikipedia.org/wiki/XY_problem
There are people (invariably young) who resist newsgroup etiquette, convinced the etiquette is pointless, or something like virtue signaling. Over the decades they eventually come around to appreciating the wisdom, even if there's never a mea culpa.
The commercial software world, and especially the Windows world, often had a much different culture than what developed online, especially in the FOSS and Unix subcultures. For the latter especially, C++ was relatively uncommon until the 21st century. C++ (with KDE, etc) and then Python had the effect of importing or creating whole new subcultures in these communities without any memory or appreciation of the pre-existing culture.
For reference I also did a search from 1998 to 2002... once again no one cares or is objecting to the term C/C++ and that term is used quite often. From this search I also just learned that Microsoft's own compiler uses the term "C/C++".
Furthermore, if something is relevant to both languages, such as a question involving pointers, why would it be a bad idea to ask about it in a C newsgroup? If anything, it's preferable to ask a question that is pertinent to both languages, especially one involving pointers, in the C newsgroup.
Certainly asking a strictly C++ question in a C newsgroup would be off-topic and rightly so, but asking a question about pointers or other low-level details that are applicable to both languages is perfectly fine in a C newsgroup.
> I'm just curious, but why is it that people in this group tend to reply with "the language C/C++ does not exist" or "C/C++ is 2, what do you mean?"
https://groups.google.com/g/comp.lang.c/c/bVBTSJ3KRrg/m/uv98... [2]
followed by 14 responses in that thread, most of which explain why that is, none defending the usage. One of the respondents is active on HN, I believe: kazinator (Kaz Kylheku).
I have a local copy of the UTZOO archives, with posts from the 1980s. Out of ~30,000 posts in comp.lang.c and comp.std.c only 284 use the phrase "C/C++". Many of those are discussing specific compilers, e.g., "Zortech C/C++" (this is especially true in other newsgroups). In a quick survey I couldn't find one where people corrected the usage, but if you read those threads most people are careful to provide answers specific to C and don't often repeat "C/C++". Presumably after C and then C++ became standardized people became more vocal about treating them as distinct.
[1] Results weren't sorted by date, and the first page of results spans 30 years.
[2] I wish I could also include a reference ID from the headers, but Google Groups apparently no longer makes them accessible even when logged in. Google Groups Usenet support is horrible, even when searching. It's a real shame. I think Google Groups has even blacklisted comp.lang.c for spam, though almost all the spam in comp.lang.c comes from Google Groups. I've filtered out Google Groups posts from my feed for the past 10 years or so.
https://www.usenetarchives.com/view.php?id=comp.lang.c&mid=P...
started by someone advertising a C/C++ tutorial.
Here, down in the replies, we can find the remark:
In the first place, there is no such language as "C/C++",
Another one:
BTW, what in the world is the C/C++ language
And:
First problem: is comp.lang.c/c++ a legal name for a Usenet forum ?
And:
Jones
16/04/2000 17:40:46 UTC
mike burrell wrote:
> x*....@m*-****a.com wrote:
> > I'm beginning a new C/C++ tutorial over at
>
> sweet. it's the c/c++ thread all over again.
Not from me! I'm keeping my mouth shut this time ;)
Indi
Look, just believe the people who were there. I was; my name appears in that thread.Another thread, same year, "NEED C/C++ PROGRAMMER", started by "ITJOBS":
https://www.usenetarchives.com/view.php?id=comp.lang.c&mid=P...
Remarks:
"No such language as C/C++."
"Presumably ITJOBS thinks "Well, I've heard of C and I've heard of C++, but I don't know anything about either. They should be about the same."
"I see this a lot and just want to add that a slash ("/") does not imply a mixture of the two, it just means "and/or", so it would read "C and/or C++".
"All the left-brained, analytical people on comp.lang.c hate "C/C++". The right-brained, "creative" people don't mind it. End of story."
"C/C++ is 1 unless C is 0 in which case the result is undefined (I couldn't resist)"
"Um, no. It's always undefined."
I'd love to know where such a thing is possible today.
If a recruiter approaches me with a C/C++ gig then I will immediately assume that either the hiring manager doesn't know what they want or the hiring manager didn't actually write the job specs, none of those scenarios sends a positive signal.
It was a pretty common correction the comp.lang.c newsgroup in the 1990s.
"Hey you dolt, there is no C/C++; they are different languages."
"Oh yeah? Well look at how when I run cl.exe, it says Microsoft C/C++ compiler!"
"Haha, C/C++ is actually undefined behavior: C++ is modified and independently accessed in the same expression ..."
The only context in which I care about "C/C++" is on resumes, where it's a sign that I need to ask a little more about the person's background.
Is that because you'd expect anyone actually experienced in either to know better than to lump them together so casually?
In my experience, it breaks roughly between half that and half recent graduates who took one C course and one C++ course.
"Next!"
https://devblogs.microsoft.com/cppblog/c11-and-c17-standard-...
MS only created their compiler to support C all the way up to C89 and it's original standard, with some Microsoftisms in it. MS did not update their compiler to support C99 and subsequent updates until, I think the late 2010s. Since then, they have updated and supported some of the newest C standards.
Then for “speed” there’s weird mashups of C++ and C# that are just littered with terrible internal build tools that harken back to a nice 2010s and the idea of:
“Idk it builds in my machine just fine”
As far as Rust goes, it’s as plentiful as F# projects (so not existing).
But that’s just what my close friend says at least.
Really, anyone senior in Microsoft shouldn't be making this sort of argument. They already have a perfectly fine memory safe language that they could use way more widely than they already do. The number of bugs in Windows that either shouldn't happen or are too hard to debug when they do, because Microsoft insist on still using C++ instead of C#, is just phenomenal. Why can Google ship a mobile OS in which large chunks including the entire GUI layer run on a JVM, but Microsoft can't ship memory safe code in Windows for even the non-performance sensitive parts because they have some irrational fear of C#?
The issues there are obviously cultural. If Rust is hard-man enough to convince Microsoft devs to adopt it when they otherwise reject C# then fine, whatever, do what it takes. But to generalize this to the rest of the software industry is silly. Most of us have been writing code in memory safe languages for a very long time, and they could be used way more widely than they are. If you want to make more code memory safe you'd be better off advancing .NET ngen or JVM AOT at this point than pushing Rust, at least they can handle arbitrary data structures in safe ways.
I'm sorry but what the fuck. I paid my fucking phone 1k€ and yet it's bewilderingly slower than a RPi4 with a native apps stack. Every single interaction in the UI is slow and has some amount of lag, even with a 120fps screen. Android is to me the very best argument against Java there is - who knows how many tens of thousands of man-hours spent into optimizing it and it just does not perform to any acceptable level even with best in class hardware. It also has the most app crashes I have seen on any platform.
That is of course still a significant restriction!
They really made the same mistake again?
This in contrast to Rust, which actually does fulfill the "off-the-shelf" promise for most use cases. It's really refreshing to be able to do `cargo build` on nearly any host and get a single binary.
Edit: Jason Turner covers C++'s ABI woes excellently here: https://www.youtube.com/watch?v=By7b19YIv8Q
https://stackoverflow.com/questions/67839008/please-explain-...
Can one link two rust static libraries communicating with actual rust symbols (not just C ones), one built with gcc-rs (assuming that this is possible yet), the other built with rustc with its default x86_64-pc-windows-msvc abi ? if not, it's at the exact same state ABI-wise than C++
I'm being facetious, but it really is both: it's too unstable in ways that are bad, and also too stable in other ways that are bad.
Edit: since you updated your comment: Rust is not in the same position as C++. C++ has an unstable ABI that it cannot break; Rust has an unstable ABI that it can (and regularly does break). Rust works around this with developer tooling; C++ largely ignores the problem and requires developers to learn the secret rules through blood and tears.
how does that work for companies that may use proprietary rust libraries? the proprietary lib authors won't recompile their shit for you just because you upgraded to the latest rustc
More realistically, the answer is to change the interface: Rust is pretty popular in software architectures where the unit of operation is a networked or IPC'd service; vendors can distribute binaries that communicate at that layer instead.
they could do this in C++ also but they overwhelmingly don't, I don't see why they would in any other language for the same target applications
See "How Swift Achieved Dynamic Linking Where Rust Couldn't" for details: https://faultlore.com/blah/swift-abi/
On a side note: I like Swift for the most part, but the last time I looked at upcoming language features they seemed like a kitchen-sink approach that's bloating the language and would better have been left to libraries. I've read this sentiment in more than one place, too.
not sure how dynamic linking would help when your boards don’t have enough (flash ?) space… the linked library still needs to go somewhere? how small of a flash medium are you using?
The busybox style of packing everything into subcommands of one big exe is admittedly a hack, but... if it works for Busybox, and it works for Go, and it works for Git, and it works for Docker, then it works for me.
many embedded boards typically have 16~64MB Flash running Linux with musl, one rust binary statically linked can easily exceeding 10MB. multi-entry is hard to manage when you have quite a few unrelated tasks, so yes I really need a true shared lib based rust for the mid-range embedded boards, which are, quite a huge number.
As you'll read elsewhere in the thread there isn't an ABI guarantee, as there also isn't so much for C++ either - but particularly for embedded you can solve this in your build process. A competent package manager in a distribution can also solve for this.
You have to include the copyright notice and license, but I almost never see that being done (and, based on the Rust projects I’ve seen, there are often tens, or even hundreds of MIT/BSD/Apache licensed dependencies).
By the way, whether you're linking statically or dynamically doesn't affect whether you ought to include the licenses of your dependencies. At least not for BSD, I'm less certain for MIT.
By choosing a license that requires attribution, developers are communicating a preference. MIT0 and 0BSD exist. If someone does not care about attribution, they would use one of those licenses.
Dynamically linking to a MIT lib is not the same as distributing an MIT lib, so yeah static linking to the lib is completely different, according to the terms of the license.
If you are working professionally as a software developer, or even just appreciate open source contributions, please take licensing terms more seriously.
Kind regards.
>Dynamically linking to a MIT lib is not the same as distributing an MIT lib
Would you mind citing the clause that makes that distinction?
> The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
When statically linking, you’re including a copy of the software, so you’re required to include the notices.
When dynamically linking, you’re not including the software.
Seems pretty straight forward to me.
Does Visual Studio (not VS Code) support Rust programming?
Are there plans for an official Rust SDK for Azure? https://github.com/Azure/azure-sdk-for-rust
They're a founding member - no idea as to the amount of financial support that Microsoft provides to the Rust Foundation....
It should work well with VS Code.
As far as I know, creating and dealing with UIs in Rust is a pain.
I’m waiting for MS Visual Rust.
My thoughts exactly.
Officially supported tools and SDKs are required in some industries. MS Visual Rust would be awesome!
It's about 'skin in the game' and dog-fooding. If Microsoft is serious about Rust, they will use it internally and support it officially.
It's easy to give an opinion on Twitter about how everyone should use Rust and stop using C / C++ for new projects.
Officially supporting Rust in your enterprise software development tools and SDKs shows that you are serious and committed to what you say.
Rust's tier 1 platform support is woefully inadequate (https://doc.rust-lang.org/beta/rustc/platform-support.html), and even the tier 3 platform list is missing some important targets. And even the platforms that it works on aren't necessarily platforms where it works well enough to be a viable alternative to C. But this guy from Microsoft's Azure who probably only ever writes software for x86 and ARM says C should be considered deprecated because Rust works really well in his specific domain.
Maybe 'memory safety' isn't the most important thing in this world. To me, writing software that does useful things in the simplest and most correct way is what matters. I get the feeling it's harder to understand my program's correctness with Rust (I mean algorithmic correctness). The C++ standard library has time and space complexity for every algorithm. I'm not seeing that's the case with Rust (correct me if I'm wrong).
Seems like a Rust sweet spot. Could you give another example? Here, it would seem this API proposal wasn't adopted because it wasn't fully baked. Isn't that a good thing?
Discussion re: Rust collections: https://doc.rust-lang.org/std/collections/index.html
So I can now add rust to this list.
It's also interesting to see this as a tweet, avoiding any worry about the nuance of the problem domain, the experience of the developers, or what problems they encounter. Sure, rust is safer than C++, but is this important to the project you work on? What sort of problems do you encounter? Would rust help? What problems would it introduce?
Anyhow, 'rust is the new C++'. I wonder what the calling cry will be in 5 years time.
As a test, someone ported FreeBSD's networking stack to Checked C. It was easy and there was no overhead to performance and binary size.
Absolutely. In fact cfront preceded cppfront by many years ;-)
C# code is out of scope for this discussion.
Perhaps it would be healthier for Rust to have competition?
https://www.linux.com/audience/developers/hacking-the-linux-...
https://github.com/alkhimey/Ada_Kernel_Module_Framework
Nvidia also chose Spark; a built in subset of Ada as being more cost effective for secure code than C++.
Assembly is also supported by Ada and I found it far easier to add than with C even.
C interface support is also excellent.
Wirth was wise to do everything possible to discourage pointer use, and make it obvious. Hejlsberg and company gave Pascal a worthy library and IDE. Then the language florished under the Turbo Pascal, and later Delphi banner.
But then Hejlsberg turned to the dark side, and joined with the MicroSith. They bought forth Sith.NET, Sith# and all other manner of evil.
The main issues are:
- Rust string types assume UTF-8, but Windows generally uses double-byte Unicode encodings. The Windows string type isn't even UTF16, because it can include invalid code points. This means that at every API call there will be the overhead of converting the string encodings and having to "deal" with invalid strings somehow.
- Rust compilation is still very slow. In C++, it was a simple matter of including "windows.h" and then start typing code. In Rust, trying to do this naively would result in terrible "inner loop" for the developers. There are some fixes, but they're fiddly.
- Enormous API surface with missing metadata. This is a problem with Rust-to-C interop in general, but the Win32 APIs are so huge that it's impractical to solve manually. There have been efforts by Microsoft to produce official and authoritative interface definitions with additional metadata such as tagging "in" and "out" parameters, etc... This isn't sufficient for Rust, which has a much more complex type system than vanilla C pointers. E.g.: lifetimes, non-null by default, etc...
At this time, programming in Rust for Windows is basically writing C++ code in Rust syntax, but with a slower compile time than C++ would have. Arguably, there isn't even much of a safety benefit, because that would require an extensive set of "shims" to be produced to make Win32 act more like Rust and less like C/C++. Take a look at the size of the .NET Framework standard library to get an idea of what that entails. Not impossible, but not a trivial effort either!
The best and most authoritative bindings are: https://github.com/microsoft/windows-rs
The "demo" looks okay at first glance:
unsafe {
let event = CreateEventW(None, true, false, None)?;
SetEvent(event).ok()?;
WaitForSingleObject(event, 0);
CloseHandle(event).ok()?;
MessageBoxA(None, s!("Ansi"), s!("Caption"), MB_OK);
MessageBoxW(None, w!("Wide"), w!("Caption"), MB_OK);
}
But if you start digging deeper into callbacks that manipulate structures that include hideous things such as lists of strings separated by null bytes, you're back in "the weeds" just like with C/C++.https://learn.microsoft.com/en-us/cpp/c-runtime-library/refe...
Kenny Kerr has done an excellent job with both the C++ and Rust bindings, but the Rust one isn’t there yet.
What I’d like to see is more use of a WinMD style metadata for the ABI for functions in DLLs you create. It would be quite simple to define a Span type that could then be imported and called safely from a diverse range of FFIs. I really shouldn’t be having to declare the ABI all over again with ctypes in Python.
Using C++/WinRT is like going back to developing COM with Visual C++ 6.0, but I guess that is what WinDev craves for.
They should have provided a proper development experience for IDL files, automatic merges of generated code, and only then, deprecate C++/CX.
Not deprecating C++/CX, and leaving us with editing IDL files with a Notepad like experience, and manually merging generated code.
Rust/WinRT is even worse in regards to WinUI tooling.
- ecosystem for GUI is weak
- Can't' imagine using anything, but relm or gtk-rs
- Existing GUI paradigms don't work well in Rust at all
As much as I love writing rust, I would rather write "core" in rust and link with it from something else for GUI.
Rust's crates.io has over 15000 packages using async. Cloudflare has just replaced their nginx with a Rust proxy that uses Rust's async. Apple has hired Rust programmers for their storage and networking teams.
Rust has been out for 7 years now, and detractors on HN still treat it as an unproven novelty that's going to collapse any day now.
Rust has given all its arguments. Has proven its goodness. What do you think it is stopping the world from adopting it?
Another year is passing. The biggest news is that it might be included in the kernel. But it just requires a bad Linus Torvalds morning to become “Rust, the language that wanted but couldn’t“.
Rust isn't aiming to replace Ruby or TypeScript. Rust is focused on being a high-performance systems programming language. It makes big sacrifices to avoid having a garbage collector, VM, or other significant runtime dependency. For maybe 99% of programs having a GC or VM is perfectly fine, and you have lots of nice languages to choose from there. But Rust focuses specifically on areas where Ruby and TypeScript are poor choices or even entirely impossible to use.
Rust's popularity has already surpassed other C/C++ alternatives like Ada, D, Nim, Pascal, Cyclone, Checked-C, Zig, and depending how you measure, even Objective-C. It is already confirmed to be in the next Linux release. None of the previous C killers got even close.
I also know there are differences and that the C/C++ crowd is more difficult to convince.
It's fitting that you mention PHP, because while the ecosystem isn't quite the same, for all it's problems (especially security), WordPress is still viable for a bunch new projects, and things may remain that way for many years to come.
I am one of the guys who would like RISC-V to be successful, then "port" everything to RISC-V assembly, without excessive usage of the macro pre-processor, then forget about compilers.
Linus T. (more likely the guys pulling the strings of the linux fondation financing) green lighted rust in the kernel, I bet this is some horrible gcc extended rust, not core and simple rust (hope they have the decency to compile linux rust code with the rust compiler written in rust). A long time ago, I had a look at rust syntax and was disappointed by the strings hardcoded in the syntax and all that "package" management system hardcoded in the syntax, but most syntax looked like a re-arranged C. Were they able to keep it that simple? (no grotesque objet orientation or those horrible templates or garbage collector or hardcoded weird and expansive memory allocation model).
The pb is C syntax is too already too complex. I wonder if rust suffers from the same issue, hope they "fixed" C: only sized types, no integer promotion, no implicit cast (except for void*), compile-time/runtime casts (without that horrible c++ syntax), only 1 loop keyword, no enum/typedef/_generic/etc, etc.
To answer your other questions: no, Rust has neither garbage collection, nor templates. I don’t know what you mean by hardcoded weird and expansive memory allocation model; Rust’s is basically the same as C++’s.
So you mean rust has grotesque and absurd object orientation like c++ (or java)? Please, say no.
Why don’t you take the time to read a Rust tutorial rather than just assuming everything bad you can imagine about it and asking people to correct you?
Many other things about rust are extremely different from C++.
So rust has heavy memory allocation implicit in the syntax (not meant only for the stack). I remember now I did not want that (like those horrible c++ new/delete).
Thx to have refreshed my memory about rust syntax.
thx anyway.
Functions can call malloc or equivalent, and while constructors don't exist, destructors do, so you can call free in them.
Additionally, I wonder if they fixed the other C issues, namely removing integer promotion, implicit casts (but different explicit casts for compile-time and runtime), enum, _generic, typeof, 1 loop keyword is enough, no switch, goto is not harmful, have only sized primitive types, change extern/static... Hopefully, rust does not have object-orientation.
And you can bet, you will find a bunch of sickos not writting simple and core rust for linux... but rust with tons of extensions only in 1 or 2 compilers like the "C" from linux which is actually the C from gcc and nothing else (clang and icc playing catchup).
I should re-read the language syntax specs though. But I guess, I would drop that reading if I encounter a definitive nono again.
Rust changed drastically before 1.0, so depending on when you read this, it may be 100% irrelevant.
> namely removing integer promotion,
Rust does not do integer promotion.
> implicit casts
Rust does not do implicit casts (often called "coercion")
> enum
Rust's enums can do what C's enums do, but are more powerful by default, you can add arbitrary data to them, not just a synonym for some integers.
> _generic
Rust has a full generic system. Very different than _generic.
> 1 loop keyword is enough
Rust has loop for infinite loops, while, and an iterator-based for loop. There's no do/while.
> no switch
Rust has 'match', which is like a switch but extra powerful, especially when combined with features like enums.
> goto is not harmful
Rust does not have goto. It would be harmful for the kinds of static analysis Rust does. Rust does have named break though, which can do many (but not all) of the things you'd do with goto.
Additionally due to RAII and the way errors work on Rust, you don't need goto for error handling like you would in C.
> have only sized primitive types,
Not 100% sure what you mean by this.
> change extern/static
I don't know what this means.
> Hopefully, rust does not have object-orientation.
It depends on what you mean by OOP, but in general, the answer is "no". There's no classes, no inheritance. You can do dynamic dispatch, but it's fairly rare.
> But I guess, I would drop that reading if I encounter a definitive nono again.
Given what you said about destructors, that hasn't changed, so sounds like you'd stop.
Before we say C must die, let's think of the modern marvel of reverse compatibility.
But sure, C++ should die. Having to look at several files to figure out how a statement works is annoying.
Hacking is still alive even if we all need paychecks.
But for greenfield projects in systems languages? First of all, that niche is tiny. There may be sub-niches where availability of some specialist library makes it harder to use Rust than C++, but I'd argue that if some library or ecosystem is that important, your project isn't completely green field. An Unreal game isn't a greenfield project even if I start now because the Engine is a massive piece of C++ you have to live with.
For anything this niche of "green field enough", I'd go with Rust even if I had a whole team consisting to 100% of experienced C++ developers. And I wouldn't even sweat the decision.
I also can’t ignore the fact that Mozilla has been in serious decline as an organization in recent years. I worry about rust’s long-term trajectory as their support of the language wanes. It’s one of the reasons I feel so positive about the future of go, as they have a lot of dedicated people on it from google (an organization that in all likelihood won’t be going anywhere anytime soon).
You can call into the Windows APIs (there's a windows crate) and if you want to call into something that isn't there, `cbindgen` and friends are amazing.
About as good as any other language with a C FFI (which is most of them).
> ... I worry about rust’s long-term trajectory as [Mozilla's] support of the language wanes.
I thought that was the whole point of having a Rust Foundation as separate from Mozilla itself.
Unity (IL2CPP) and Monogame (BRUTE) transpile the C# (byte)code to C++ to be able to deploy to consoles and the C# version they support lags several versions behind.
I don't think we can call C# "the new King of gamedev" until it is officially supported by console makers but it seems unrealistic for a couple of years.
Hopefully C# 7's NativeAOT fixes this (Sony & Nintendo will probably need to ship a runtime for C# for this to happen), I don't want to deal with transpiling stuff, I just want C# support out of the box.
What I have in mind is just making a game that can run on PS5/Xbox/Switch without using anything other than C# itself (and the platform API). No engines.
I vaguely remember proof-of-concepts/experiments on Nintendo Switch that made it possible to deploy NET Core AOT builds, but it was in some gitter chatroom so sadly I can't find it again.
Anyway, we still have at least a decade before C# or something else with GC takes over. C# is good enough, but something similar to Swift would make me happier.
Not really. SDL, SFML, Monogame and FNA (and more) do not have editors, but a lot of popular indie titles are shipped with them.
> folks who willingly toss all that aside to write a game from scratch are among the fringe
Check out Dear Imgui. Indie shops such as exok (makers of Celeste) and AAA companies such as Rockstar Games (GTA) use it to create editors for their games.
You don't really need an engine. You probably need a framework if you're going cross-platform. If you're exclusive, you don't even need that.
If we start depending on proprietary engines instead of platform APIs, we're shooting ourselves in the foot in the long-term.
Even programmer-focused pipelines tend to evolve into designer and artist focused pipelines over time. It's simple: Dear Imgui doesn't solve the problem of rapidly iterating on an asset from Blender/Maya/Houdini; or from rapidly iterating on level design and scripting; or rapidly iterating on sound import and design; or... Over the course of development many indie studios end up reinventing tools that are already cheap or freely available.
What it looks like is another Raylib, Allegro, Ogre, etc; an engine these days can be expected to have tooling for artists and designers first and foremost.
Especially for networked games.
As of now, Rust does not have a spec: https://users.rust-lang.org/t/where-is-the-rust-language-spe...
I agree that Rust needs a specification, but this is post-hoc: C is popular in embedded because it's the systems programming language that survived the 1970s and 1980s, in no small part thanks to the GNU project.
Tried Rust, did not like it that much, compared to D.
All kidding aside, as others have pointed out this is coming from someone with tremendous credibility and it is worth giving some consideration. I have a lot of respect for Rust although I've only toyed with it for personal projects. The compiler provides very helpful messages (vast majority of the time), but even so, for complex applications it can still be very difficult to reason about.
As has already been mentioned, it doesn't seem to be anywhere near prime time for GUI applications (such as those built with Qt, Gtk, Win32, etc.). I don't think it's fair to say that ALL GUI apps should be built with a managed language.
Like with go, one of the nice things is that there's just one provider of the compiler. At least you don't have to contend with different levels of support and different compiler options.
The case for replacing C++ is a lot stronger but I don’t see game engines, for instance, switching to Rust (or using garbage collection) any time soon.
I just read a few C++ vs Rust comparisons online yesterday and didn't see anything about a significant difference in security or reliability. Mind you the articles weren't very technical.
How is Rust so much more secure and reliable than *modern* C++?
just because I don't have to deal with 15 compilers, 15 IDEs, 15 build systems, decades of language experiments, kind of compiler-flags driven development
Nice.
Does that hold true for cross compiling to arm (Rpi specifically) and Android?
Remember when python was simple? And you just had setuptools? Popularity breeds complexity and fragmentation.
I was not able to figure out how to get it to build, maybe someday I'll fire up a VM running XP and whatever version of Visual Studio was popular in 2006 and try again.
Modern C++ is really nice (I write mostly C++17 and later for work), and does a great job of obsoleting bug-prone patterns from earlier versions of the language. But it's still very easy to introduce memory corruption (of either sort), especially for less experienced C++ engineers. Some kinds of corruption (like double frees) have become even more common as beginner mistakes, in my experience, thanks to the complex mental model required for move construction (compared to Rust, where moves are statically checked).
The best thing I've used so far is clang-tidy (specifically the "use-after-moved"[1] check). It catches some stuff though, which is better than nothing.
[1]: https://clang.llvm.org/extra/clang-tidy/checks/bugprone/use-...
Move constructor. Constructs the container with the contents of other using move semantics. Allocator is obtained by move-construction from the allocator belonging to other. After the move, other is guaranteed to be empty().
https://en.cppreference.com/w/cpp/container/vector/vectorWhich can be a useful property at times, but also means tooling won't help you here since it's not an obvious bug.
This doesn't change the surrounding point however, which is Rust's philosophy of safeness by construction: if a particular piece of code is safe, then no safe (i.e., invariant-preserving) use of it can be unsafe. That alone makes Rust's security properties strictly better than those of C++, where even the modern safer paradigms can violate underlying invariants.
Rust catches things like use-after-free at compile time. *modern* C++ still lets things slip through e.g.
#include <iostream>
#include <string>
#include <string_view>
int main() {
std::string s = "Hellooooooooooooooo ";
std::string_view sv = s + "World\n";
std::cout << sv; // oops, use after free
return 0;
} clang++ -std=c++17 test.cc
a.cc:7:29: warning: object backing the pointer will be
destroyed at the end of the full-expression [-Wdangling-gsl]
std::string_view sv = s + "World\n";
^~~~~~~~~~~~~
In any case, I think the philosophical differences between C++ and Rust are well understood, and the different views of the cost/benefits there are also well understood.In practice, rust will take over when it convinces enough C++ developers that the tradeoff is worthwhile.
That rarely happens by CTO's, or anyone else, telling everyone they are doing it wrong, but instead by helping people see easier ways of doing things, and ways to get work done faster/etc.
Or, you know, waiting for everyone who does it the old way to die.
My bad. I should have been more modern. Try this one:
#include <iostream>
#include <string>
#include <string_view>
int main() {
std::string s = "Hellooooooooooooooo ";
std::string_view sv {s + "World\n"}; // {now even more modern and warning free}
std::cout << sv; // oops, use after free
return 0;
}This is why I say it takes extra work to get things wrong. Every example purporting to show "unavoidable" memory faults is super contrived. You have to turn off compiler warnings to be able to miss it.
It might seem contrived, and it is, but it's the essence of a bug that has happened in the real world, distilled to a 10 line example.
And yeah, "use things properly or they will blow up", but enough people don't do that (or mostly do but occasionally slip up) that it becomes a problem.
Of those use-after-free bugs that exist, they are a large source/percentage of the exploitable security bugs in C++ apps for sure. But again, it's not like apps are usually just littered with use-after-free. Like you may find one in a several million line of code app. They are not that common of a mistake, and FWIW, 100% of them are catchable with things like MSAN.
So people make mistakes. C++ makes certain kinds of those mistakes easy. Rust makes them hard or impossible. I don't think you will find any disagreement about this.
Again - this sort of thing is not going to convince anyone to use rust that doesn't want to already, for lots of reasons, not the least of because they think they are unlikely to make mistakes that matter :)
All this sort of thing does it turn people off from considering it for real, when they should!
(and i say all of this as someone who is funding efforts to replace billions of lines of C++ - i have no love for C++ over rust or vice versa. I just think the current approach here seems very unlikely to result in increased adoption)
For sure! It's those one-every-million-lines-of-code ones that are the problem, and that slip through code review and rear their head only in production at odd hours of the day.
> this sort of thing is not going to convince anyone to use rust that doesn't want to already
My post was in reply to someone asking the question what does Rust give you over modern C++, and this was an example showing that modern C++ still has its holes.
I'm not a Rust absolutist, nor do I think everything should be written (or rewritten) in Rust, but the biggest thing going in its favour is that offloads the cognitive load of checking lifetimes and ownership to the compiler, and that turns whole classes of runtime bugs in to compile time bugs.
clang++ test.cc -std=c++17 -Werror=dangling-gsl.
test.cc:7:29: error: object backing the pointer will be
destroyed at the end of the full-expression [-Werror,-
Wdangling-gsl]
std::string_view sv = s + "World\n";
^~~~~~~~~~~~~
It is pretty standard in large codebases in any language to carefully choose sets of warnings and errors.I do think Rust has lots to offer, but i think the eternal argument here about what the compiler lets you do vs not is not likely to be a winning one with the C++ developers you see who don't want to move over.
If you want to write safe c++ you have to understand memory and lifetimes and what the code is doing. Humans have been shown to be quite bad at doing this - even experienced programmers.
Rust offloads that work to the compiler.
If you try to touch a data structure from a wrong thread, it will stop you at compile time. You don't need to fuzz such problems under a sanitizer. You have a compile-time guarantee for your entire codebase and even your dependencies. If you try to use a thread-unsafe library from a parallelized code, it won't compile, and it will show you exactly which field of which struct needs to be wrapped in atomic or mutex to work (at this point people say "but what about deadlocks!?". They are very easy to track down compared to heisenbug memory corruption.)
This makes parallelization of code relatively easy and way more reliable. Rust markets this as "Fearless concurrency".
Look at it from the perspective of someone brand new to C++. How do they know what is "modern" and the right way to do things, versus "legacy" and the wrong way to do things? As a beginner, there are thousands of resources available to you on the internet -- some new, some decades old -- with code of varying quality that may or may not be "modern". All of it is valid C++ and will compile, but some of it may have footguns that are nonobvious to the new programmer. There's no "modern only" compiler that will reject said footguns, because C++ takes the position that leaving the footguns there is a feature.
This isn't the case with Rust. Maybe it will become more like C++ in the future as the language changes, only time can tell. But for now, code that compiles in Rust is guaranteed to be free from various classes of bugs that still are possible to compile in C++, despite "modern" C++ having fixed various issues.
Another way of saying this is that "just use modern C++" is a variation of "you're holding it wrong" or "just don't write buggy code", which has proven not to be scalable advice that leads to safer software.
I do. This is Microsoft.
That language makes a train take a dirt road. It’s big, complex, and I have to believe “not what we are actually looking for”.
Haskell promised all kinds of safety too and has back doors to hide “unsafety” that are basically “game over”. Rust doesn’t seem to do much better in this regard. Maybe I’ve not written enough of it. (I’ve written far more Haskell)
How bad is GC really? Has Go shown it to be manageable and not an issue yet?
Seriously spending all my time in C and C++ due to the nature of my job, I can’t say I’m convinced we’d ever start using Rust.
I mean it’d be nice to be able to write M1/M2 Mac OS native Ada code but no one offers that it seems.
Maybe it's possible to hire c++ dev and make them work on a rust project?
Anyhow, is there a qt equivalent for rust? Can rust really compete with c++?
I've read rust code and I'm sorry but it seems like the steep learning curve is just not worth it, even if the benefits are big.
I still believe rust fills the same niche of ada, meaning tight requirements. Most c++ projects don't care that much. It's cheaper to test things or rewrite than betting on a new difficult language.
Maybe, but not after proclaiming to the internet "your job is obsolete".
Read his internals book - much appreciated back when I was doing Windows programming. Used his tools - very nice while I was still using Windows.
But I never looked to Mark Russinovich or any Microsoft guys to advice on what programming language to use. What’s the point of making such an arrogant proclamation?
I'd agree today you totally shouldn't be starting new projects in C-with-classes style C++, and take advantage of all the newer tools available in newer versions instead. Sure, Rust and similar may have even better tools to help the programmer, but talking about raw productivity, especially in shorter projects, learning a new language and all the fumbling and mistakes and anti-patterns that can hurt the result, as well as longer-term maintainability, may be worth consideration. Especially, as even if the core project is brand new code, the library ecosystem it's working in may still be more mature around other languages.
It totally makes sense to me relegating C and older-style C++ to systems where it's really the only choice (platforms with older/poor tooling, places where the resulting code requires more massaging than usual like resource-limited embedded situations and the developer is already skilled in this with their current toolchain, other situations that no doubt some people will find etc etc.)
The library ecosystem in Rust is less mature (there isn’t a library for absolutely everything), but where a library does exist it tends to be much more robust than the C++ equivalent. A library in Rust will not have UB (however you call it). It won’t throw exceptions. It won’t return null without warning you, etc.
The difference is that "discouragement" is in the compiler itself not external lint tools (though many of those "lint tools" are just optional arguments to the compiler). The big difference is the general community having less of a spread of opinions on what the recommended subset is, not helped by that changing over the age of the language, and not being clear about what the general epoch of the language are to highlight things that may be generally replaces by a better construct. Honestly, I'd say the biggest failing of the C++ updates today are lacking some similar epoch system - where older constructs can actually be deprecated from the language.
It would be interesting to see if rust gets exactly the same thing as the community expands, and accumulating language updates affect the generally accepted best practices. It's clear Rust doesn't intend to be completely static, with significant language features being added every version. I wonder if one day we'll look at today's rust in the same way as someone focused on "modern" c++ looks at c++98 C-with-classes style code.
Everyone uses a subset of any language, that's what coding styles and common patterns are. A definition of this subset is a really useful thing you can do for any non-trivial project IMHO, for any language.
You seem to have misunderstood my point. Whether or not you (or I) happen to be using this or feature of a language is irrelevant; the question is whether it's valid input to the toolchain.
For comparison, the existence of an SQL injection vulnerability in example.com has nothing to do with whether you or I happen to exploit that vulnerability or not.
W.r.t. Rust: the mere existence of "safe" and "unsafe" subsets, which (a) can be explicitly permitted or forbidden, and (b) are well-defined and don't differ from person to person, org to org, etc. makes it much more practical to forbid "unsafe" from as much of our code as possible, and to pin-down precisely those locations where it has been used. The same cannot be said for e.g. "modern C++"
If you’re writing something safety-critical, sure, use a memory-safe language like Rust/Go/etc. Otherwise, I think C++ is still plenty viable.
That is why i think the criticism is very very valid
In other words, Msft has a long history of suppressing competition by steering the industry away from doing things that could threaten Msft’s dominance: like moving your company from the C++ language you’ve mastered to a new modern language you don’t know well.
He has been at Microsoft forever. He really knows hot air.
But to be fair it feels more ready than rust did at 1.0
For example, in Rust 1.0 having a destructor increased object size. This was in no way acceptable as a final design, but they made a plan to fix it in a compatible manner, and actual work was postponed and other things were prioritized. It was fixed one year later in Rust 1.12 without any compatibility problem.
Rust was unusually aggressive about this to ship 1.0 as soon as possible. In general, if it could be fixed compatibly, it was postponed. From what I can observe, Zig doesn't seem to do this, so I can believe Zig now is more polished than Rust 1.0. If so, remember it was a deliberate choice of Rust developers for Rust 1.0 to be unpolished.
For example, Dropbox started to use Rust in production before 1.0, see https://blog.convex.dev/a-tale-of-three-codebases/
It would not surprise me he praises Python =)
Opinion discarded. Sorry.
I'm glad I don't have a Twitter account. I'd have spent the whole day arguing with stupid replies (both for AND against OP's point).
Obviously geek’s rant is still a rant.
> ... if we used all the effort gong (sic) to develop Rust and port everything over to Rust to instead just improve the wrinkles that exist in C++.
If you read the tweet, you might notice Mr. Russinovich isn't actually advocating porting everything to Rust. If you'd care to explain how one might iron out the little wrinkles in C++, you have a captive audience.
Um, he is who?
> without proposing any real solutions
If he is Mr. Russinovich, he is saying, "For the sake of security and reliability. the industry should declare those languages as deprecated." Sounds like a proposal to me?
https://github.com/carbon-language/carbon-lang/blob/trunk/do...
This is a very long term strategy but it makes sense viewed that way.
Until they rewrite mrustc in rust everyone using rust is one dependency up.
The truth is we don't need rust, either you are making a server and then Java is the language to use.
On the client where rust has a good chance to compete with C we're looking at electricity cost problems and then C is an easy choice.
You need to compile things to be productive.
If you'd please review https://news.ycombinator.com/newsguidelines.html and stick to the rules when posting here, we'd appreciate it.
https://www.zdnet.com/article/linus-torvalds-rust-will-go-in...
>> For everything else, there is javascript.
Scientific / numerical computations? GPU / CUDA programming? Machine learning? Natural language processing?
But idk what OP is saying lol
Incidentally if you're going to do it, I recommend pytorch over tensorflow.
We serve CRUD here, sir.
If it's not running in the browser it should simply never be JS. That is the only environment where you are stuck with it. Almost anything else is better but you should probably using one of Java/C# or Kotlin/Rust in 2022.