4 ms·
It's not that Rust catches these issues like a sanitizer or linter would, it's that they can't exist by design. The compiler is aware of potential type-, lifeti
by paavohtl 5y ago
It's not that Rust catches these issues like a sanitizer or linter would, it's that they can't exist by design. The compiler is aware of potential type-, lifetime- and ownership safety issues, and you don't need to run any code to figure out if your code is memory safe or not; static analysis is enough.
Also, even if Rust only caught by itself what Clang and half a dozen analyzers would catch, you also get a really nice language as a bonus. There is much more to Rust than just safety.
- benreesman 5y agoSo, I'm not really sure how the distinction between `rustc` and the government-issue `clang` chain really matters unless one is a lot faster, and they're both really slow. The by-design thing I get for like something with a port open, but as a default? It's been a few months but the last time I was trying to hack a Rust project printing stuff out hit the borrow checker. I can live without that.
- paavohtl 5y agoYou've mentioned the printing issue a couple of times in this thread, and it sounds pretty weird to me as a someone who has used Rust for a couple of years. Without knowing the specifics I can only assure you that if you know the basics of the language, you'll have no issues printing whatever you want whenever you want. Rust is admittedly a language you can't just jump into without spending some time learning the fundamentals. If you try to do anything non-trivial without grokking the basics of ownership and borrowing you are bound to run into frustrating issues.
- db48x 5y agoHe probably tried to do dbg!(foo), which takes foo by ownership and consumes it. Doing dbg!(&foo) will accomplish the same thing (printing foo along with the line number and file name), but because it only uses a reference to the foo, it won’t consume the original. This is perfectly sound and logical once you know the explanation, but it is pretty weird to a newcomer.
- benreesman 5y agoThe project was alacrity and my checkout is on a laptop I don’t have on hand at the moment so unfortunately I can’t gist my patch, but I’ll have that box tomorrow and I’ll try to remember to do so. I was attempting to use whatever all their other logging was using. ‘&’ was the first thing I tried because I’ve done the tutorials and then some, but after that got the borrow checker arguing about my new line of code as well as two others I didn’t touch, I rotated through all the other sigils brute force, IIRC it was a combination of commenting out another line and ‘’ that got me a log line. Now maybe that’s on alacrity because maybe they do ownership in a weird way. But even in Haskell, even as a novice on stackoverflow, ‘unsafePerformIO’ will get you a line printed to STDERR, and it’s not 50-80s to build 50-ish kloc every time. I like learning programming languages, I like working on compilers, this stuff is basically my only hobby. But as the TF2 people are learning the hard way, if a complete novice can’t get a log line in without understanding a bunch of novel context, PyTorch is taking your SO out to dinner pretty soon. Now if Rust could build a million lines of code in 1-5s like it should be able to (and like it seems that e.g. Jai can) I wouldn’t care. I needed to get stuff done in C++ bad enough that I learned template metaprogramming, which I wouldn’t wish on an enemy. If Rust made my builds 50-100x faster in low optimization settings, I’d write it on clay tablets. But what I actually get is a comparably slow build, a comparably “!$&@>>>>”-heavy syntax, yet another failure to do macros that impress a Lisper in a curly brace language, and now the static analyzer’s usually good advice is mandatory and can’t be turned off to do a quick experiment. I always have to watch my cynicism because I’m a bit autistic and I offend way more often than I mean to, but if I’ve got 1MM lines of C++, I’ve got a pain in the ass on my hands. If I start porting any meaningful part of that over to Rust, now I’ve got two giant pains in the ass.
- paavohtl 5y agoInitial builds are indeed quite slow, especially when a project has a lot of dependencies. However, in most cases further builds are not that bad. I have never built Alacritty from source so I don't really know if there are any specific issues with it, but from my experience incremental builds take just a few seconds in medium sized projects. Additionally during development a full build is usually not necessary all the time; oftentimes it's just enough to check the code for errors with `cargo check`, which is usually significantly quicker than building a full debug binary. Edit: I tested building Alacritty from source on my computer (Ryzen 5600X, Windows 10). The initial build (consisting of 130 crates) took 34 seconds. Building again after adding a single print statement took 6 seconds, and `cargo check` took about half at 3 seconds. It's not ideal by any means, but IMO it's not also unreasonable for 25K lines of code, plus those ~130 dependencies.
- astrange 5y ago> It's not that Rust catches these issues like a sanitizer or linter would, it's that they can't exist by design. Not saying this is true about Rust, but I find these approaches dangerous because they can move bugs off to a different meta level where they're harder to detect. For instance, some people make safe C dialects where signed integer overflow wraps around or variables are auto initialized to 0. Well, what if you didn't want to overflow at all or 0 was the wrong value? Now you can't find the bug because the program has been redefined to do the wrong thing instead of simply crashing.
- paavohtl 5y agoI get how those concerns would apply to a C dialect, but not really to Rust. Since Rust is an entirely new language you shouldn't expect it to work exactly like C, unlike you would expect of a C-derived language. Most of Rust's safety features are handled at compile time, and they are usually handled explicitly, not implicitly. A few examples about initialization: * An instance of a struct is created by giving an initial value to each field. Leaving out any field is a compile error. Since structs are always completely initialized, you can't accidentally pass references to partially initialized structs like you could in a C++ or Java constructor. * All local variables must be initialized. Accessing a variable before initialization is a compile time error. * Structs have no implicit default value. The default value can be defined by implementing a trait, either by yourself or by deriving it with a macro (which would default integers to 0 and so on). Default values are only used by a fixed set on functions in the standard library, and never implicitly. The overflowing case is one of the only cases where Rust is a bit more implicit. Integer overflow is checked at run time in debug builds (so over/underflow causes a panic) and defined to wrap around in release builds. However, the standard library also defines methods on numbers which explicitly use wrapping, saturating or checked (either return a Result value or crash) semantics.