From European perspective, Russia's latest invasion was a wake-up call that the peace isn't permanent, and diplomacy and economic power may not be sufficient to keep it.
Effectiveness of drones and advanced missiles in the war was also a wake-up call that semiconductors and batteries have a strategic military importance, and the rest of the world is quite dependent on China and Taiwan for these.
I assume that all the talk about trade deficits and unfair competition from Chinese EVs is bullshit, and the US and the EU are having an "oh shit" moment realising they're unprepared for the world where wars are fought with drones and robots.
No, I am not suggesting this. And to my knowledge neither did Russia at any point suggest this. If Russia did, kindly share. The probability that Russia will invade Europe is propaganda propagated by western media. Request you to watch the 2 videos I have linked above.
You are, in fact, either suggesting that or are entirely unaware that Ukraine had a peaceful agreement with Russia prior. The entire point of giving Ukraine official sovereignty was to reduce international pressure on Russia - everyone knew that reneging it would bring war to Russia's doorstep, it's written in black and white on the Budapest memorandum.
You can blame Russia for not knowing their worth, but they did break the treaty and there is no rational justification for doing so.
But that is what you are insinuating about Ukraine. We should not have let the Ukrainian people self determine their path and instead given them the cold shoulder and left them to Russia.
Rust can be optionally compiled in a panic=abort mode, but by default panics are recoverable. From implementation perspective Rust panics are almost identical to C++ exceptions.
In very early pre-1.0 prototypes Rust was meant to have isolated tasks that are killed on panic. As Rust became more low-level, it turned into terminating a whole OS thread on panic, and since Rust 1.9.0, it's basically just a try/catch with usage guidelines.
> Could such bugs be avoided in C using the right tools and strategies
"right tools and strategies" is very open-ended, almost tautological — if you didn't catch the bug, then obviously you haven't used the right tools and the right strategies! In reality, the tools and strategies have flaws and limitations that turn such problem into "yes but actually no".
Static analysis of C code has fundamental limits, so there are bugs it can't find, and there are non-trivial bugs that it can't find without also finding false positives. False positives make developers needlessly tweak code that was correct, and leads to fatigue that makes them downplay and ignore the reports.
The more reliable tools require catching problems at run-time, but problems like double-free often happen only in rare code paths that are hard to test for, and fuzzers can't reach all code either.
Static analysis of arbitrary legacy code is limited. But I do not find it difficult to structure my code in a way that I can reasonable exclude most errors. The discussion of false positives in C is interesting. In some sense, 99% of what the Rust compiler would complain about would be considered false positives in C. So if you want to have safety in C, you can not approach this from this angle. But this relates to my point. If it is acceptable to structure the code in specific ways to make the Rust compiler happy, but you do not accept that you may have to write code in specific ways to avoid false positives in C, then you are already not comparing apples to apples.
Even if you rewrite C code to the same "shape" as Rust, it won't become equally easy to statically analyze. The C language doesn't give the same guarantees, so it doesn't benefit from the same restrictions. For example, pointers don't guarantee their data is always initialized, `const` doesn't make the data behind it truly immutable, and there's no Send/Sync to describe thread safety. You have nothing to express that a piece of memory has a single owner. C's type system also loses information whenever you need to use void* instead of generics, unions with a DIY tag, and have pointers with a mixed provenance/ownership.
Rust checks that you adhere to the analyzable structure, and keeps you from accidentally breaking it at every step. In C you don't get any compiler help for that. I'm not aware of any tools that guide such structure for C beyond local tweaks. It'd be theoretically possible with enough non-standard C language extensions (add borrowing, exclusive ownership with move semantics), but that would get pretty close to rewriting the code in Rust, except using a bolted-on syntax, a dumb compiler that doesn't understand it, and none of the benefits of the rest of Rust's language, tooling, and ecosystem.
You do not get the same automatic guarantees when not using external tools. But you get almost the same results when using tools readily available and having a good strategy for organizing. I do not have problems with double frees, void type unsafety, or tagged unions in my code. I occasionally have memory leaks, which tooling then tends to find. I certainly have exploitable integer overflows, but those are easily and comprehensively mitigated by UBsan.
> If it is acceptable to structure the code in specific ways to make the Rust compiler happy
I think this is a misleading way of presenting the issue. In Rust, there are class of bugs that no valid Rust code can have (unless maybe when using the "unsafe" keyword), while there is valid C code that has said bugs. And here's the difference: in Rust the compiler prevents some mistakes for you, while in C it is you that have to exercise discipline to make sure every single time you structure the code in such a way to make said bugs unlikely. From this, it follows that Rust code will have less (memory-related) bugs.
It is not an apples to apples comparison because Rust is designed to be a memory safe fruit, while C isn't.
The point was that you can not reject warnings as part of a solution for C because "it annoys programmers because it has false positives" while accepting Rust's borrow checker as a solution.
I think the general point of my comment still stands, as you and everyone else working on the project would need to be disciplined and only release binaries that were compiled with no warnings. And even using -Werror doesn't fully solve the problem in C, as not having warnings/errors is still not enough to get memory safety.
I don't really disagree with you, but I was also making a slightly different point. If you need absolute memory safety, you can use Rust (without ever using unsafe)
But you get 99% this way with C, a bit of discipline, and tooling and this also means maintaining a super clean code base with many warnings activated even though they cause false positives. My point is that these false positives are not a valid argument why this strategy does not work or is inferior.
Your claim is that it is inferior because you only get 99% of safety and not 100%. But one can question whether you actually get 100% in Rust in practice in a project of relevant size and complexity, due to FFI and unsafe. One can also question whether 100% memory safety is all that important when there also many other issues to look out for, but this is a different argument.
I don't think it's a common concern in Rust.
It used to be a problem in Internet Explorer. It's a footgun in Swift, but Rust's exclusive ownership and immutability make cycles very difficult to create by accident.
If you wrap a Future in Arc, you won't be able to use it. Polling requires exclusive access, which Arc disables. Most combinators and spawn() require exclusive ownership of the bare Future type. This is verified at compile time.
Making a cycle with `Arc` is impossible unless two other criteria are met:
1. You have to have a recursive type. `Arc<Data>` can't be recursive unless `Data` already contains `Arc<Data>` inside it, or some abstract type that could contain `Arc<Data>` in it. Rust doesn't use dynamic types by default, and most data types can be easily shown to never allow such cycle.
It's difficult to make a cycle with a closure too, because you need to have an instance of the closure before you can create an Arc, but your closure can't capture the Arc before it's created. It's a catch-22 that needs extra tricks to work around, which is not something that you can just do by accident.
2. Even if a type can be recursive, it's still not enough, because the default immutability of Arc allows only trees. To make a cycle you need the recursive part of the type to also be in a wrapper type allowing interior mutability, so you can modify it later to form a cycle (or use `Arc::new_cycle` helper, which is an obvious red flag, but you still need to upgrade the reference to a strong one after construction).
It's common to have Arc-wrapped Mutex. It's possible to have recursive types, but having both together at the same time are less common, and then still you need to make a cycle yourself, and dodge all the ownership and borrow checking issues required to poll a future in such type.
Weights in neural networks don't always need to be precise. Not all weights are equally useful to the network.
There seems to be a lot of redundancy that can be replaced with approximations.
This technique seems a bit similar to lossy image compression that replaces exact pixels with a combination of pre-defined patterns (DCT in JPEG), but here the patterns aren't from cosine function, but from a pseudo-random one.
It may also be beating simple quantization from just adding noise that acts as dithering, and breaks up the bands created by combinations of quantized numbers.
Mixture of experts involves some trained router components which routes to specific experts depending on the input, but without any terms enforcing load distribution this tends to collapse during training where most information gets routed to just one or two experts.
Keep in mind that the "experts" are selected per layer, so it's not even a single expert selection you can correlate with a token, but an interplay of abstract features across many experts at many layers.
The warp model in GPUs is great at hiding the DRAM latency. The GPU isn't idly waiting for DRAM.
All threads that need a memory access are in a hardware queue, and data coming from the DRAM immediately dequeues a thread and runs the work until the next memory access. So you compute at the full throughput of your RAM. Thread scheduling done in software can't have such granularity and low overhead, and hyperthreading has too few threads to hide the latency (2 vs 768).
Effectiveness of drones and advanced missiles in the war was also a wake-up call that semiconductors and batteries have a strategic military importance, and the rest of the world is quite dependent on China and Taiwan for these.
I assume that all the talk about trade deficits and unfair competition from Chinese EVs is bullshit, and the US and the EU are having an "oh shit" moment realising they're unprepared for the world where wars are fought with drones and robots.