Rust 1.47
blog.rust-lang.org
blog.rust-lang.org
So whereas a generic implementation of Display for Vec of any length was possible, Arrays required one implementation of Debug per possible length of the array.
I know for my no_std work, const generics for arrays can't come fast enough.
Especially when passing a number of things to a function, and you need to pass ownership. You can't do that with a slice, because that's borrowed, so a Vec used to be the only option. Now there's a one option more that's going to be more lightweight than allocating a Vec :)
Unfortunately there are many limitations with arrays in Rust at the moment, which make it more annoying than it should be. Generics over the array size is one of them, although unfortunately there are others such as https://github.com/rust-lang/rust/issues/53827
It's the single worst aspect of working with Rust. I am very happy.
People wanting to use const generics themselves will want to follow this issue, which is about stabilizing a minimally-useful subset of const generics: https://github.com/rust-lang/rust/issues/74878 . It seems to be coming along well: "Regarding the remaining steps: there are only a handful of issues I think are blocking min_const_generics at this stage (several of which already have open pull requests). We also want to add many more tests, which is something anyone can easily help with. If you want to tackle one of the issues, feel free to ask @lcnr or myself how to get started; I'm going to dedicate time to fixing whichever remain."
However in this case, these are const generics, so you no longer need to use macro to generate [char;1],[char;2]...
You just write [char; N] where N is const. Compiler determines which values of N are used and generates for them an appropriate version.
Const generics still aren't stable. I believe the GP was talking about the list of new `const fn`s in the release (near the bottom of the post).
Basically, const functions can be used in places regular functions can't because they are directly "run" by the compiler at compile time.
Const functions let you run code to define const values. This code will be run at compile time before the const values are inlined.
For example let's say you have a constant for PI but you need 2*PI. You could do the multiplication in const context, meaning the multiplication will happen during compilation and not execution. Slowly more and more of the language is becoming usable in const context so more advanced things can be done during compile time.
Compile-time function evaluation is also one of the features of the Jai programming language. If you can't get people to use your language, getting them to steal all your features is a good consolation prize.
It's difficult to use Jai as long as it only exists on Jonathan Blows computer, he still hasn't released it
Making them const just formally guarantees the compiler can evaluate them at compile time which makes them useful in more contexts.
Was the point of my answer.
`const fn` is merely an API guarantee that the function can always be evaluated at compile time if the arguments are themselves known at compile time.
> When you have a small team that write tests and a compiler that is on the boundary of interactive speed, compiler speed dominates performance.
e.g. char::is_ascii_alphabetic() was made const in 1.47, but 1.46 would already run it at compile time: https://godbolt.org/z/hWf65f
The difference is in 1.47 you can use the result to assign something that must be known at compile time.
> Shorter backtraces
This is a very welcome change! Having to find the "root" of a full stack trace can easily take 30 seconds, which really starts adding up.
fn concat<T,M,N>([T; M], [T; N]) -> [T; M+N]I did an experiment with units of measure years ago in Rust: https://github.com/coder543/metric
To me, it felt ergonomic, and it was absolutely compile-time type safe to the extent you would expect. It worked just fine. I know of quite a few other libraries that do the same thing with their own unique approaches, so there are many flavors of this that all work on stable Rust.
If you're asking for something like this to be built into the standard library... that's very unlikely to happen in the foreseeable future.
most numbers i deal with in my code have units somewhere. mistakes happen. i don't want to choose from multiple unique approaches, i need the ecosystem to standardize on one solution. see also the async task executor problem in other languages.
But, yes, you probably could transmute it... if you really have to.
The reality is that the conversion cost to just `map` one Vec to another is extremely low on anything but maybe a microcontroller —- and even then, maybe not.
If you benchmark things and can’t find a safe way to do things, there are unsafe methods, but I am highly skeptical that they would be needed.
It’s also extremely possible to fork such a library, change a few lines to use the dimensionally correct type, and be done with the issue.
If all of your heavy lifting is being done by this external library anyways, and that library just uses raw floats... why bother with the ceremony of using a dimensionally safe float in your own code if the performance cost of mapping between types is too high?
The real benefit of dimensional safety is when you’re actually doing computations, not some external library you pulled in.
Rust allows for these zero cost wrapper types that will do exactly the correct computations as if they were done with hand written code... but you have to actually have computations that you want to do. The type system intentionally doesn’t want you to treat these typed floats as regular floats. That’s the point.
But there are ways to transmute certain types for no performance penalty, they’re just footguns you should avoid except as an option of last resort.
Every audio library I've seen so far operates on (*i16/f32, size_t) or &[i16/f32]. An audio library which supports dimensioned values is hypothetical. And most dimensioning libraries don't have a unit of "sample" (in time) or "audio amplitude" or "channel", so the audio library won't even know what unit system to pick.
> It’s also extremely possible to fork such a library, change a few lines to use the dimensionally correct type, and be done with the issue.
And suddenly the audio library is tied to your specific unit system, and you still need transmutes or whatnot when talking to the OS sound library.
> If all of your heavy lifting is being done by this external library anyways, and that library just uses raw floats... why bother with the ceremony of using a dimensionally safe float in your own code if the performance cost of mapping between types is too high?
Most of the time I end up just using a named type alias, instead of a strong newtype.
#![feature(const_generics, const_evaluatable_checked)]
fn append<T: Copy + Default, const N: usize, const M: usize>(
xs: &[T; N], ys: &[T; M]) -> [T; N + M] {
let mut result = [T::default(); N + M];
result[..N].copy_from_slice(&xs[..]);
result[N..].copy_from_slice(&ys[..]);
result
}
fn main() {
let arr = append(&[1i32; 3], &[2i32; 4]);
dbg!(arr);
}A classic example of them being used in Rust is to be generic over arrays, like what the blog post talks about. Arrays encode their length as part of the type; [T; N] is the type of an array of Ts that’s N elements long. In other words:
fn foo<T>(array: [T; ?]) {
How do you define ? to work on any length? When const generics is implemented, you’d write fn foo<T, const N>(array: [T; N]) {
and now you can call this function on arrays of varying lengths.There's a bit more to it than that, but that's the core of it. Does that help?
Correct.
> How do you implement map, fold, etc., that work on an entire collection regardless of length?
So, while arrays exist, there are also things like slices and vectors, which have a runtime length, rather than an array's compile-time length. So that's one bit of it. But the other part is that these are implemented on iterators, rather than on the type directly, so usually what happens is "turn that into an iterator, then do map/fold/filter/whatever on the iterator. It is easy to convert the compile-time length array to a run-time length iterator, so it ends up being a uniform interface.
However, often times it entirely compiles away to nothing. What this may help with is bounds checks; it is possible for this to make it easier to remove/hoist bounds checks in some circumstances. In my understanding.
[1,2,3].iter().map(|x| x + 1)
https://doc.rust-lang.org/std/iter/trait.Iterator.htmlRust seems to be overally punishing
You make the sacrifice of a "punishing" compiler, and spending more time writing code, but you gain software that's more likely to be "correct", safe, and not leak memory.
Really, as in all things computers, it depends what your set of requirements are as to what trade offs you make
Intuitively it makes a lot of sense, and it jives with my subjective feelings (especially for longer-lived projects), but I'm not sure if there have been any studies to back up that claim.
https://danluu.com/empirical-pl/ is a good place to get started on this topic.
Moving from one of those languages to a modern statically typed language can come with a feeling that your programs tend to run successfully as soon as they compile --- certainly they do more often than they would in Ruby. Because the compiler is doing some of that testing work for you. It's a good feeling.
But it hasn't been my experience that the extra rigor in Rust's model produces the same boost from Java or Go; in fact, my first-run experience with Rust is generally less reliable than Go; there are a few more things that can go wrong with a Rust program and slip by the compiler.
Which is what you'd expect; Rust isn't garbage collected, so the programmer has to do the garbage collection, and every program is responsible in some sense for designing and implementing that part of its own runtime. There are things you can get wrong there that GC'd languages don't make you bother trying to get right. And, of course, if you take the time to get your per-program runtime really right, there's a performance gain to be had from doing so. It's all tradeoffs.
This seems like a really odd thing to say in at least two dimensions. Firstly, I would say that "the programmer has to do the garbage collection" isn't an accurate way to describe Rust. Secondly, and particularly in comparison with Go, Rust's RAII applies more universally than Go's garbage collection. How many times have you seen a missing defer or a defer inside of a loop? I've seen both quite a bit. But those bugs basically don't happen in Rust precisely because the programmer almost never needs to deal with destruction directly. It's done automatically by the compiler.
As to the broader point, I would very strongly oppose the notion that Rust is less reliable than Go. While I don't think I would argue that Rust gives the same boost over Go that, say, Java or Go give over Ruby (that's a tough argument to make anyway, even if I agreed with it), I would say there is a meaningful boost. But that's a tough argument to make too. Aside from the obvious bits (nil errors and forgetting to check errors), for me, it basically comes to my belief that Go punishes its practitioners for abstraction. I wrote a bit more about that here: https://users.rust-lang.org/t/what-made-you-choose-rust-over...
Another point, which to your credit you didn't make but which is nonetheless true, is that I am not a good Rust programmer!
I don't think Rust is less reliable than Go in the large. I do think there are more things you have to get right in a Rust program than in a Go program, so it's "less reliable" in that weird twilight state when you're first bringing up your program.
I do agree that Go punishes practitioners for abstraction. If you're, like, you, that's a very bad thing. If you're working with a team of people for whom the project is a means to an end and not a brilliant-cut gemstone, putting the brakes on abstraction can be a good thing, which I think a lot of Rust programmers will quickly learn after the nth time they've had to do an edit-compile cycle just to `let () = something` to figure out a type.
The point about having too much power is taken, and I don't have experience with that in a team context. And yeah, I am not exploring the Rust downsides as much here, and there are definitely others.
Although you could characterize it as "Rust makes the programmer think about and describe the garbage collection."
Really, I think most argumentation comes down to “the type system of the programming language I want to use anyway is the right one, and everything else is wrong”.
If I'm slinging together an internal CRUD app, the extra time thinking about types probably will slow me down because the major risks aren't really type problems.
But if for example I'm working on something in a game engine, being able to use the language and compiler to enforce assumptions/invariants at compile time is really useful.
The much bigger problems imho are not really tractable. e.g. consider something that does:
struct server {
std::vector<requests> m_requests_to_process;
boo m_running{true};
void on_web_request(request req) {
m_requests_to_process.push_back(req);
}
void process_pending_requests() {
while(m_running) {
for(auto req : m_requests_to_process) {
do_stuff(req);
}
// oops, forgot to clear
}
}
};
there's no "leak" in the OS sense as everything will be reclaimed upon server::~server... but your memory usage will be strictly increasing. Can Rust detect those cases ? As in my experience this is the most common leak pattern (of course not in a simple example like this, but when your "server" architecture starts being split across multiple threads and source files...This particular case might be because you would probably consume the vector in the loop, which would free, but you could absolutely write the exact same code in Rust with the same end result.
However, it may help in this specific case.
In your example you are iterating over `m_requests_to_process`. As you are using `auto` instead of `auto &` it automatically clones the elements of a vector. In Rust, it's not possible to clone an element by accident. Objects are moved by default (think `std::move`) and if you want to clone instead you need explicitly use `.clone()`.
If `do_stuff` function takes ownership of a request (as in, if it takes `Request` parameter and not `&mut Request` parameter) than the problem will be pointed by Rust, and so the compiler wouldn't allow you write code like this forcing programmer to write code that removes elements from the list to take ownership of them. For example:
for req in mem::take(&mut self.requests_to_process) {
do_stuff(req);
}
`mem::take` (https://doc.rust-lang.org/std/mem/fn.take.html) replaces an object behind a mutable reference with a default value for a given type (empty vector in case of vectors) and gives you an ownership over vector. struct request {
int id;
double parameter_value;
};
surely moving does not gain anything - the original vector object still keeps the memory allocated, right ? sure, if you have complex requests with substrings, etc, but in that case I'd have `const auto&`-ed :)(from my experience going full-throttle on movability when C++11 came out, I'd say that this was a mistake overall, much better to keep things as const& most of the time if you can. I've not yet reached a state where I consider the need for ownership transfer a code smell... but not very far :-))
You could also do something with the drain method (which they posted originally and changed to the current implementation, not 100% sure why) and that would keep the memory around, yes, but then you'd be with only the high water mark of the number of requests, because it would be re-used.
`Vec::drain`: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.dra...
Keep working at it. After a while you start to realize the patterns that work. Now, I can prototype in Rust pretty fast.
There are also a lot of nice features in Rust other than the pure absolute runtime efficiency.
> There are also a lot of nice features in Rust other than the pure absolute runtime efficiency.
Certainly! I reread my earlier post and see how it could have been more qualified; what I meant to say was if the burden of the borrow-checker is so high that the user needs to use the ~Rc~ by default /I/ would find it hard to justify Rust for /that/ type of programming over other languages with similar features.
> it seems to me that it would defeat the point of using Rust at all and go with a strongly-typed GC language.
This seems to be a regular comment when talking about Rust (among other "incremental improvement" approaches) and I don't really get it: for 95% of the code things are simple enough that you don't have to think too much about it, the other 5% can either rely on one of the multiple-ownership safe abstractions or use unsafe. To me this framing sounds like "why do I need seat belts, if I fall of a cliff it won't do any good!"
> To me this framing sounds like "why do I need seat belts, if I fall of a cliff it won't do any good!"
I’m sorry that that’s how you read my comment — the languages I tend to use are much higher-level than Rust, like Haskell and Lisp, and I constantly found myself having to restructure my code to deal with memory-management. In particular, I found closures and futures difficult to work with — compared to a higher-level GC language. This experience may or may not be typical; I have few data-points to draw on after all!
Though I have found that the borrow checker often ends up pushing architectural changes on me as I'm fixing things.
This might be because I'm just newer with Rust, but I personally would find resolving 30 borrow-checker issues at once to be much more painful that resolving them as I go.
In C having to free allocated memory manually dictates how data structures are built and how your program flows. Often you have to keep track of extra state in order to free your memory at the right time and if you don't have this in mind from the get-go you're going to write code that leaks a lot of memory or doesn't work. The same is true for rust, but instead of the code leaking or not working it doesn't compile. If you turn those checks off with unsafe you're essentially stuck with an improved C that's just as difficult to prototype in.
Systems programming languages are simply not designed for fast prototyping, instead focusing on fast and in rust's case correct code. A GC, dynamic typing, high level library, etc. all help you prototype faster but you're not going to be able to use them to write an OS or a web browser.
Rust has very strict checks, and we -want- those. That's why we're using Rust in the first place.
I -could- use a more convenient / lenient language like ruby or golang but I generally wouldn't prefer it unless the use case made sense. You end up "paying" in different ways later down the line as your codebase grows in complexity.
In my experience, the rust compiler is extremely helpful and most issues I had went away after reading the rust book. [0]
The difference between Rust and Go, on the other hand, is mostly pragmatic: Rust is "strict" about design and implementation details Go's runtime handles for the programmer; there's nothing for Go to be "strict" about.
Rust is more rigorous than Go, but to a much smaller degree than Go is over Ruby.
Regarding memory management, sure, but Rust's strictness also handles things that Go doesn't. Two examples are error handling --- Result<T,E> in Rust ensures that you check for errors before using a result --- and thread safety --- the borrow checker prevents many synchronization errors that Go doesn't catch.
Rust gives a hard shove where Go gives something closer to a nudge, but in practice, Go's nudge (the requirement to do something with an error or else bear the shame of _'ing it) gets me 99.999% of the way to Result.
Rust has an `Error` trait too, and you can always just use `Box<dyn Error>` as your error type if you're fine with using a heap allocation to avoid caring about the concrete type (which is what's happening in Go when you use the error interface as your return type anyhow). Rust just makes the more efficient (in terms of runtime performance, not necessarily usability) the default and the more expensive option opt-in. This is a common pattern in a lot of the language design choices: performant by default, with the option to opt into a less performant variant to make things easier if you're okay with the cost. I think a lot of newcomers to the language (not saying you are one; I have no idea what your experience level is) don't realize this because the Rust community tends tends to _really_ like doing things the "proper" way. This isn't a problem per se, but I think there would be immense value in having more resources that made all of the options on the performance versus usability spectrum more clear.
One could argue that outside of safety guarantees that Rust provides it also happens to be a good language that people would like to use for those reasons (I really like the tooling, ecosystem and standard library when it comes to Rust, not so much the language itself).
Rust has many quality-of-life improvements that could be transplanted to a more relaxed GC-based language, but that won't be Rust any more. Here are some musings how such language could look like:
https://without.boats/blog/revisiting-a-smaller-rust/
(OT: why OP got downvoted so hard? It's a reasonable question to ask)
I also am disappointed that the OP got downvoted. Seems bad.
Ultimately I did get a solid explanation here. If I want a quick, fast and dirty language , Rust doesn't fit the role.
I really do love how C# gives me the ability to hack things together quickly, with still stopping me from doing things which simply won't work. Flutter takes this even a step further with the dynamic keyword( C# has dynamics too , but they aren't as robust ). I can write function calls with dynamics which is great for prototyping. Eventually bad things will happen if you use dynamics in every single call , but it helps me get started.
I definitely understand why many software developers see this as a dumbing down of software engineering, which I would attribute the downvotes to.
I would never write a large production app in Python though (having done it a couple of times). The flexibility becomes unwieldy at that scale and you have to have tests that exercise every corner or you'll have problems hours or days into running.
With Rust do you need less Unit testing ?
I find myself upvoting tons of comments in Rust threads where those comments are just asking questions, but are, for whatever reasons, downvoted. Happens on the Rust subreddit too. I don't know wtf it's about.
I too don't like rust evangelism around here. But any developer should know at least one system language, understand algorithm complexity, understand basics about memory management and caches, etc.. And probably it is easier to learn rust than C++ to those with web background.
With that stated, I would encourage you to understand why rust was designed this way and why the strictness of the compiler is actually a major advantage compared to languages like Python and JS where a lack of a type system actually makes the software much more prone to bugs.
There are also some immature crates for tracing garbage collection in Rust, like rust-gc, which typically has higher throughput than reference counting.
But as an aside, if you're just trying to prototype quickly, some useful "shortcuts" can be:
- Using `Box<dyn std::error::Error>` for functions which need to handle a result
- Using `unwrap` or `expect` to easily access Option internal values
- Using `unimplemented!()` if I'm trying to mock an API design. This one is nice because it will let you build out the signature including specifying a return type without having to build out the function logic.
Obviously these are shortcuts and not production suitable, but can be good to just get some code on the page that compiles
In retrospective, I make the life harder:
* Thinking like in the other langs I have learned (with exception of my first 2) is enough to just read fast some tutorial and start coding... I relent and pick a book to learn it right.
* Start worrying so much about performance, when never before I bothered much (what! this can ALLOCATE!). Now I clone like madman!
* Try to fit the OO mentality to Rust. Even in F# I don't fully commit to POCO objects and functions as I do in Rust now. Also, the lacks of polymorphism is what hurt me sometimes (ie: is harder in rust)
But now? Rust feel ABSURDLY productive. The thing I notice is how much I refactor stuff now, (even more than in F# that also was a up in this regard).
The "punishment" parts is only in my toy interpreter and very small now. For my main project ( a ERP/ecommerce app rewrite from F#) Is great!.
There's nothing preventing you from using multiple languages on your app. Say, Rust for foundations and Lua/Python/Scheme/Tcl/Whatever for glue.
All the core tools I tested works 100% and almost all the crates work. A few, like libc and Nix, still needs explicit riscv64 support.
Haskell is cool and all but every time I tried it, I spent too much tle with package management for example.
Also you can't really ship an app in Haskell.
Frankly, I did nit see people releasing proper desktop apps for some time now :( Electron apps do not count.
That said, it is really really tough to get all the little behaviors that people rely on. Including all keyboard shortcuts (across all platforms), double/triple clicking words, etc.
I guess that this may not matter that much for specialized software (but please focus on the damn textboxes, they are hard to get right). I'm just commenting in case other people decide to follow the same path.
Also, for a broader audience: be mindful of accessibility. Usually, this kind of thing doesn't work with screen readers.
Another problem is with the package ecosystem. It feels like most of Swift ecosystem is wrappers around Apple APIs.
There are also some strange workflow edge cases like the fact that you currently cannot use Metal shaders in Swift Packages. This is due to the fact that Xcode projects are supposed to be ephemeral (not version controlled, but generated when you clone the package). However if you want to compile Metal, you have to add some compiler options. As a result, every time you add a dependency, you have to regenerate the XCode project file, you have to fuck with your XCode project to add the compiler options.
Ironically, you can use Metal in Rust crates just fine.
Rust is also truly cross-platform. Windows and Linux have first class support.
To summarize my argument, Swift feels like daddy Apple is telling me what is best for me which may or may not be true. Rust feels like true empowerment. If there is something that doesn't suit me for whatever reason, there is generally a way of working around it.
I guess it depends on what you are doing. Swift is OK for iOS/macOS development but other than that Rust is more advanced. Rust macros are really powerful, things that need to be added explicitly to the Swift compiler can be implemented as Rust macros.
Yep blazing fast indeed. /s
Rust is one of the nicest languages out there. Very well thought out, elegant, full low-level control for real systems programming (sorry Go!) AWS uses it a lot, Microsoft is starting to use it.
Go, or even Python is better if you just want to make a backend API for a (web) app. You'll be more productive with it over Rust because you have a GC and can ignore the whole ownership issue for the most part. Python for very small teams likely to stay small for a long time, Go otherwise.
C++ has come a long way, but it's still hairy and loaded with footguns and baggage. I would only use it these days if I needed to use a big C++ library (like a game engine).
I am no longer willing to use Haskell, PHP, Perl, Java or JVM languages, .NET or anything else that's not Go, Rust or Python. With the same caveat as C++ above. I pass over job postings that require them. That's not saying those languages are bad, just that in my personal opinion there are better tools out there, and if I'm going to work with it day in and day out, it had better be in something at the top of my list - because life is short.
Yes, it is not super massive, but it is in the production path for important things, and appears to be on quite an upward trajectory.
I do not work at Amazon but I do have a couple of friends there both in Seattle and Vancouver.
Everybody wants to look cool from the outside :-), blogging about how you're using Java in 2020 is not cool.
Just think that it took C++ 40 years to reach where it is now and still there are domains where C rules, a systems language that people forget is only 10 years younger than COBOL.
It has been picking up a lot lately, Apple, Amazon, and Microsoft are all showing some adoption, for instance.
> I remember trying it out back in 2014 and saw nothing of interest, as a Haskell user
The interest for a Haskell user would be that you have some of the functional programming features you like (such as discriminated unions!) with C/C++ levels of runtime performance/efficiency. For someone who has no need for that level of low level control/performance, Rust is generally not a language you want to use, for sure.
> A lot of the main "selling points" of Rust are getting introduced in C++
It is true that you could, with sufficient coding standards and linters, get something approximately like Rust by using C++, where the linter disallows any non safe pointers, any use of null or nullable types without wrapping it in a variant, disallowing all cases of undefined behavior, and so on. However you would have something a lot less pleasant to use than using Rust in the first place, build times would probably end up worse with those thing enforced as a build step, and setting up such an environment would be non trivial and you basically are just building rust out of C++, twine and gum, so why not just use Rust?
my 100% honest answer: Rust does not have Qt
rust-qt[0] doesn’t support inheritance at all, so you can only connect to things in Qt which accept callbacks using slots. It requires `'static` lifetime on those callbacks, so as far as I can tell you are also forced to use `Rc`s whenever you are doing something with a rust-qt object even if you should be able to use a plain reference. The code is auto-generated, so all APIs are `unsafe`, and no function overloads means names are gross because the function signatures must be expressed in the function name (e.g. the `QMessageBox` constructor[1] becomes `QMessageBox::from_icon2_q_string_q_flags_standard_button_q_widget`). This could be improved by using `Option`s for arguments with defaults, but right now this is what it looks like.
qmetaobject-rs[2] has some support for inheritance but as far as I can tell it’s limited to a couple of base types only. It’s also designed around using QML, so it doesn’t actually expose most of the Qt API. As such I don’t have too much experience with it.
I’m unaware of any other usable Rust Qt bindings right now. I currently make things work by using rust-cpp[3] to create C++ subclasses and smuggle events, but this sucks because it also means the objects on the Rust side need to have the Qt API re-exposed manually since AFAIK there isn’t a way to have Rust handle that without using a code generator. (There might be some hackier ways to make this work, or maybe someone with more Rust experience than me knows of something smarter that could happen, but in any case the ergonomics right now are not good for the average developer.)
[0] https://github.com/rust-qt/ritual
[1] https://doc.qt.io/qt-5/qmessagebox.html#QMessageBox-1
https://github.com/woboq/qmetaobject-rs
The 1.0 release was in 2015, and there wasn't much industry adoption before that. Today most of the big tech companies are using it for something. Microsoft published a series of articles this year about using Rust internally.
> A lot of the main "selling points" of Rust are getting introduced in C++.
In the C++ world, Rust's biggest selling point by far is memory safety. The safety story is based on notions of ownership, borrowing, and lifetimes that are built into language itself. Most of the standard library, and many foundational crates like Serde and Rayon, have designed their APIs around these concepts. These things tend to go "all the way down": Every single function or datatype that deals with references defines its lifetime requirements for those references, and every single callsite of one of those functions or variable of one of those types is statically checked to meet those requirements.
I wouldn't go so far as to call this an "all or nothing" thing. Languages like TypeScript make it clear that you can get good value out of a strict type system even when much of the ecosystem isn't strict. But there's a lot of value in being on the "all" side of the fence here -- especially for languages with pointers and destructors -- and I think it's unrealistic to expect an established language like C++ to make that many changes.
> Also, what is it about Rust that gets automatic top view on HN?
Having a new, serious contender in the C/C++ world is exciting! And maybe Rust being more challenging to learn makes people more excited about being "in the club" when they do learn it. On the other hand, all the talk about memory safety seems to make some people kind of...self-righteous?...about the language, which we would all prefer to see less of :p
Now that the application has grown to be quite huge I really struggle to maintain the python code, I miss static typing. Big code changes are a pain to validate and regressions always manage to slip in the cracks. Meanwhile I've used Rust for some smaller, less critical components and it Just Works. C-tier perfs and zero crashes in 4 years.
I'm definitely optimistic for the future of the language at this point. The community is thriving and the language keeps improving, while not breaking backward compatibility and forcing me to update my code to make use of the latest features.
As they stand I thought that they took a lot of effort to write and maintain for very little practical value.
As for use in the industry, I see it mentioned every now and then and I keep being surprised because I have low expectations of its adoption, but then suddenly there are big things like Dropbox rewriting their synchronization core (Nucleus) in Rust, and Microsoft releasing Rust bindings for their next-gen Windows API (WinRT).
So I guess it's still rare in the very large realm of software development, but probably more popular than one may expect for a bit of a fringe language. One that I first thought would remain a proof of concept and point of discussion in computer science circles. I'm happy to be wrong because I think it does solve some long standing problems in certain projects.
Obligatory clarification: the compiler enforces that there are no _data_ races; there can still be other types of race conditions.
The compiler does nothing to prevent data races over shared memory IPC mechanisms across processes, which happen to be the way everyone that cares about security is turning back to, concurrency + processes.
this isn't surprising; it's a very different kind of language.
> A lot of the main "selling points" of Rust are getting introduced in C++.
kind of true, but also really not. features from rust are indeed being copied to c++, but imo the key difference between the languages is the attitude towards memory safety. memory safety is "opt-in" with c++, while it is "opt-out" in rust. I doubt this will change anytime in the near future.
1. It is a very interesting language. Personally I find it fascinating (coming from imperative languages). Some blog posts are really worth the high ranking.
2. It's an enthusiats language. They tend to be emotional on their subject. That's why Rust is indeed overpromoted compared to other languages. People getting their stuff done are often using boring tools like Java, C/C++ or Go and are not hanging around here in language threads very often.
Rust is not prevalent in the industry at all. People reporting how it's used by Microsoft and Amazon etc. are not telling lies, but often forget to see the big picture. Compared to C/C++ or Java Rust's usage is tiny. Less than 1%. I'd say even less then 0.01 % worldwide in terms of people using it, lines of code written daily, project budget spend on. But how often are people writing posts "Why we adopted Java" or "How we improved backend performance by 300% using C++"? Rust is kind of vocal, so the overall picture of it's usage is quite distorted.
Still, the usage of Rust has been going up the last 5 years. So it is gaining. And it's a great fit for certain tasks.
I gather from the description that this is not enabled by default. Is that correct? If so, why isn't it enabled by default? It would seem to fit with Rust's focus on safety.
In general, we update regularly to gain access to bug fixes and because upgrading regularly makes each upgrade easier, so we don't need something specific to trigger an update.