Rust 1.34.0
blog.rust-lang.org
blog.rust-lang.org
I've followed the issue closely because it's one of the features used in Ruma, my Matrix homeserver and libraries. In fact, for the library components of the project, it was the last unstable feature. With the stabilization of these APIs, I'll finally be able to release versions of the libraries that work on stable Rust. This will happen later today!
>> Can you eli5 why TryFrom and TryInto matters, and why it’s been stuck for so long ? (the RFC seems to be 3 years old)
> If you stabilise Try{From,Into}, you also want implementations of the types in std. So you want things like impl TryFrom for u16. But that requires an error type, and that was (I believe) the problem.
> u8 to u16 cannot fail, so you want the error type to be !. Except using ! as a type isn’t stable yet. So use a placeholder enum! But that means that once ! is stabilised, we’ve got this Infallible type kicking around that is redundant. So change it? But that would be breaking. So make the two isomorphic? Woah, woah, hold on there, this is starting to get crazy…
> new person bursts into the room “Hey, should ! automatically implement all traits, or not?”
> “Yes!” “No!” “Yes, and so should all variant-less enums!”
> Everyone in the room is shouting, and the curtains spontaneously catching fire. In the corner, the person who proposed Try{From,Into} sits, sobbing. It was supposed to all be so simple… but this damn ! thing is just ruining everything.
> … That’s not what happened, but it’s more entertaining than just saying “many people were unsure exactly what to do about the ! situation, which turned out to be more complicated than expected”.
https://this-week-in-rust.org/blog/2019/03/05/this-week-in-r... https://www.reddit.com/r/rust/comments/avbkts/this_week_in_r...
Lol; that was me (although there were probably others). I approve of the dramatic rendition.
> The never type [is] for computations that don't resolve to a value. It's named after its stabilization date.
For others having trouble to grok that sentence, ! is the never type. Should never happen. https://doc.rust-lang.org/std/primitive.never.html
This is the first such instance of "oops, turns out that wasn't safe after all, that should have been unsafe" that I've heard of in Rust. Is that because this is the first such mistake since the 1.0 milestone (the rest of `unsafe` having been nailed down before 1.0), or have there been other such mistakes that I didn't hear about because I haven't read the notes for all of the prior releases of Rust?
The resolution of this not only had a notable effect on how Rust thought about memory safety (in particular, that leaking memory could not be considered unsafe as it's always possible to construct a leak using safe Rust if you have access to Rc, and as a result `std::mem::forget()` was changed from unsafe to safe), but also informed the way we used RAII going forward, as the fundamental unsafety was due to the use of an RAII value as a token representing external computation and was not itself used in order to perform that computation, which meant leaking the token didn't prevent computation from happening. In all other known cases of RAII, leaking the value is safe because without the value, you can't access the protected resources, but in this case the token represented a thread and the thread of course would continue to run after you leak the token. As a takeaway from this lesson, you can't use tokens to represent external processes, and probably shouldn't use them to represent e.g. hardware that needs to be put back into a known state when the token is dropped unless you have a mutex in there as well (which would cause deadlock if you drop the token and then reuse the resource, rather than sending bad commands that break the hardware). Instead, any time leaking the token would cause unsafety, you need to structure your code to use explicit scopes instead, such that the library can clean up at the end of the scope.
There have been some small soundness holes in the typesystem that we have fixed, resulting in breakage, but since that’s in the language, that’s the only way. A library API is different. There haven’t been many of these though. We did have some point releases which immediately fixed some library errors that were introduced by a release, see 1.15.1. But that was in a new API, and so the chance of breakage was extremely low. This API has been around for years. It is also not used much, given it’s a *NIX specific extension you have to explicitly import.
Note that upon using it, you’ll get a warning, so everyone will at least be notified.
Isn’t Rust 2018 effectively Rust 2.0 (since it introduced new keywords and requires changes to old code if a user opts in to Rust 2018)? So the function could be made unsafe in Rust 2021 (or whatever it’s called).
The standard library cannot change with editions for exactly this reason. It’s compiled with a particular edition, like any other crate, and so can’t work differently in different editions.
Given the tight relationship of all of these parts (despite each one being capable of being individually versioned), it would seem feasible to add a cfg attribute for the Rust edition, and then make the function unsafe if the user had opted in to Rust 2021 (or whatever).
Think of it this way: crate A uses edition 2015. Crate B uses edition 2018. There’s only one copy of the standard library. It can’t be compiled both ways.
If, in theory, we let you have multiple copies of the standard library, maybe that could work, but that’s not possible nor desirable for a host of reasons.
glibc has a similar commitment to never breaking user code, and yet symbols have been removed from glibc! The trick is to use "symbol versioning"; code compiled against old versions of glibc is transparently rewritten to use the old versions of symbols, while code compiled against new versions is rewritten to use the new versions of the symbols. [0][1]
You can imagine something similar for the Rust standard library, whereby both the unsafe and safe versions are provided, and packages are transparently rewritten to use the correct version based on their specified edition. You don't need two copies of the stdlib; just of the symbols that have diverged. In this case, you wouldn't even need two versions of the symbol in the resulting binary, since the addition of `unsafe` doesn't change the codegen of the function, but merely restricts what code is accepted by the compiler.
It's true that this would require some serious shenanigans in the stdlib, but it's a tractable problem. It's also, in my mind, quite acceptable for the standard library to play games like this, since the compiler, the language, and the stdlib are always going to be tightly coupled, and the complexity can be shielded from users.
All that said, it sounds like the list of deprecated stdlib features is nowhere near long enough to justify adding this kind of complexity.
[0]: https://gcc.gnu.org/wiki/SymbolVersioning
[1]: Note that symbol versioning is kind of a quagmire, but that's because it's seriously underdocumented and practically no developers are aware that it exists. The idea itself is sound.
I think what you’re saying is “it is possible to do this with the correct design” and what I’m saying is “that design has not been proposed nor accepted and so the answer today is “that’s not possible”.” Does that sound about right?
And great! All I wanted to point out was that, should the need arise, it is technically possible to tie stdlib function signatures to a particular edition.
Why would it not be possible to have some additional information that says "from rust edition 2021 onwards this is actually obsolete". Whether crate B merely gives a warning on compilation or an error then depends on crate B's edition.
Sure that means you can still use the method if you really want to (by using older editions), and it also means that if some of your dependencies are still on an older edition you can't prevent it from being used by them, but it would be a higher hurdle to accidental usage.
There may be a way in which it is possible, but it is not currently possible. We’d have to have a different design.
What about code examples from StackOverflow, or Github issues? Will these work without adjustments in my local project?
Will a future syntax highlighter always be able to highlight the code in my old Rust articles?
Will future tooling always be able to read my current code?
Can I make editor macros and snippets that will keep working in every version of Rust?
If I can write code in one crate and it will compile, but then write it again in another, newer crate and it doesn't, then it isn't backwards compatible. Plus, as noted above, "code will keep compiling" isn't even a guarantee that the language team gives you.
2. Same thing. You can construct an example that breaks any language in existence.
3. Yes.
4. Yes.
5. Yes.
6. You’re using an idiosyncratic definition, so yes, it’s not the same. Backwards compatibility is about the same thing continuing to compile, not about changing things and expecting it to still compile; that’s forwards compatibility.
I also don't know how current code running in a future compiler is forward-compatibility. And the Rust guarantee only kind-of holds if you define "code" as "crate". Everything outside of or crossing that boundary is not compatible.
To clarify and bring it to an example: Are you guaranteeing that `(a<b, c>(d))` will always be parsed as a tuple with two comparisons? Because if so I believe you're the only one.
Totally the correct way to go about it, IMO. Thus my comment about deprecation.
>> There will not be a Rust 2.0.
>> Note that upon using it, you’ll get a warning, so everyone will at least be notified.
:/ That I've mixed feelings about. Why not? Is it because of the fiascos between Perl 5/6 and Python 2/3? Deprecations and warnings about using deprecated features are indeed the correct thing to do, but IMO, aren't the whole picture. I think to all the times I went to compile something, and got to watch a constant stream of warnings for it (or worse, got hit by bugs I shouldn't have because the programmer took time to finally suppress that annoying warning pointing to the flaw in his code). A (very occasional) major version bump to show "These things we found out were actually wrong and said that you shouldn't do N years ago? We meant that, those are gone now," strikes me as the Right Thing for a language with a major focus on correctness, like Rust.
But, since I'm here armchair quarterbacking here on HN, instead of getting my hands dirty building a major language, I'm willing to concede that my opinion might be different were it informed by experience.
Rust does have a strong commitment to safety, but not an absolute commitment to correctness. These things happen very infrequently. Is it really worth taking an extreme action (which a major language version bump is, especially in the systems space) just to turn a few warnings into errors? Currently, we don’t think so. Maybe in 20 years, when (And if! :) ) there is more than one standard library API that suffers this problem, it would be worth it, but at the current time, it just doesn’t seem to make sense.
I think I'd expect to see warnings about the existing safe method being deprecated for a while, then it's complete removal at the time of another edition of Rust. Users of older versions of Rust can still use the removed function, but newer editions ban it.
This could be implemented as a reserved STD function list in the compiler if it must, since as you've mentioned we only have one STD lib atm.
Editions cannot make this kind of change, as also discussed below.
Never mind the fact that the function is still a symbol in the STD library.
I understand if this is too much complier magic, though it seems like the correct idea to me anyway.
Am I missing something?
P.S. symbol version pinning seems like a great idea, I've even dreamt of having exposed syntax for it, e.g. `Foo::<i32>::bar@v1.3.2(arg1, arg2)`.
Sorry if I'm not making my thought very clear.
I hope I didn't come off as being to negative about the change. Warnings are still a pretty good solution here.
We can’t get rid of it because we have a commitment to not breaking users’ code. There will not be
a Rust 2.0.
This is interesting. The C Standard people have, for example, removed “gets” from the C11 standard.
Go, too, has exceptions to its Go 1 Compatibility Promise[1], which include security, unspecified
behaviour, and bugs, both in the language and in the standard library. I don't remember for sure,
but I think there were things removed from C++ specifications as well; please correct me if I am
wrong. Did Rust decided to never break stdlib compatibility because the mechanism of editions was
considered from the start, or was this rather ad-hoc?We have to do such things extremely judiciously though. Users can only tolerate so much breakage, even if you say “we did say we reserved the right to do this.” This API is just so rarely used that it was judged not a good time to pull the “technically we are allowed to do this” card.
When you don't have a standard, you're left at the mercy of languages promising not to break stuff. If they do anyway, your options aren't as clean as just sticking to the older standard.
This is not really true though. The commitment is about publicly visible and crater-testable code. If you have your own code in-house, there isn't much guarantee unless all syntax/code you use is widely used in public as well. A known change in language grammar will be evaluated on its publicly visible impact, not on its general breakiness.
It's really disappointing to keep reading about guaranteed backwards-compatibility and then being told in RFC discussions that those don't exist.
If backwards compatibility is guaranteed, turbofish cannot be "fixed". I can't find the link currently, but from my reddit post on this discussion the crucial quote from a language team member was:
> Our bar for doing backwards compatibility breaks has never been soundness fixes. We have in the past done changes given future-compatibility warning with lints and then made such changes without an edition.
The turbofish discussion also contains this quote:
> This RFC technically amounts to a backwards incompatible change without using the edition mechanism. However, as the RFC notes, a crater run was made and the syntax was not encountered at all.
You can see how controversial that RFC was, and for that exact reason.
Can you point me towards an authoritative post in the turbofish discussion that says that it can't happen because of backwards-compatibility changes? Because before it was locked it seemed that the language team wanted to go ahead.
I've been repeatedly told by language team members that the policy you're promising people doesn't exist. I would really appreciate it if there was further clarification.
My understanding is that, again, some lang team members want a different policy. That doesn’t mean that it’s actually different.
So, can you point me to a comment that tells me that the policy still holds and is as you are presenting it?
I think I'd prefer PRs like https://dependabot.com/
This feature is for alternate registries that _supplement_ crates.io
"riscv64imac-unknown-none-elf and riscv64gc-unknown-none-elf targets are now on stable rustc 1.34.0 :slightly_smiling_face: https://github.com/rust-lang/rust/blob/master/RELEASES.md#ve...
https://github.com/rust-embedded/wg/issues/218#issuecomment-...
EDIT: Mea culpa, I somehow missed that it _is_ in the release notes, but still, it's worth pointing out. I hope it'll find its way into Fedora/RISC-V.
The language as such is already quite good, in spite of one or other possible improvements on borrow checker ergonomics (e.g. callbacks).
Many commercial use cases require distribution of binary libraries, Rust community might care about winning those customers, or just let them go and leave them to keep using the languages that fulfil such use cases.
Sounds like caching these would be a simpler but solution.
> Many commercial use cases require distribution of binary libraries [...]
Good use case, and in this case another cache would solve the issue as well. Defining a protocol for binary caches and being able to add your own could solve this very well. The same solution could help solve the previous one too.
BTW, if you are in either case, have you looked into Nipxkgs[1]? They might be able to do both, the basic capabilities are there, not sure if the Rust infrastructure[2] already provides it.
[1] https://nixos.org/nixpkgs [2] https://nixos.org/nixpkgs/manual/#users-guide-to-the-rust-in...
Any ideas on when this will be? There has been talk about faster compile times for years now without that much apparent progress.
There has been a lot of progress, it’s just been slow and steady. For example, since the first of 2018: https://perf.rust-lang.org/compare.html?start=2018-01-01&end...
Really? What makes you say that? Have you tried it?
$ git clone git://github.com/BurntSushi/ripgrep
$ cd ripgrep
$ git checkout 0.4.0
$ time cargo +1.12.0 build --release
real 1:09.13
user 2:06.08
sys 2.839
maxmem 359 MB
faults 1292
$ cargo clean
$ time cargo +1.34.0 build --release
real 22.484
user 2:32.66
sys 3.380
maxmem 702 MB
faults 0
That's a >3x wall-clock speedup over the past 2.5 years on a cold start. That's pretty good.Also cold start speed is not really what I care about. I am more concerned with compiler speed while working and running tests. I find that if a language compiler is to slow it breaks flow while testing changes. I haven't seen much mention of the improvements the incremental compiler gives in a while. Last I read was the 2017 blog post [1] during beta and it only showed modest improvements and more recently I only see talk of how it still needs a lot of work [2].
[1] https://internals.rust-lang.org/t/incremental-compilation-be...
[2] https://nicoburns.com/blog/rust-2019/#compile-times-especial...
I don't follow compiler performance developments. I'm just responding to clarify that there has been performance improvements. They have likely just built up over time. I don't think there was any one specific change that dramatically improved things.
[0]: https://github.com/bjorn3/rustc_codegen_cranelift/issues/381
Even for things where debug mode is too slow, Cranelift could be a game changer since it promises to produce more performant binaries than LLVM in debug mode (Idk if it will be fast enough for you use-cases though).
I just wanted to point out that Cranelift won't solve the compile-time issue all by itself.
I'm surprised that making people run their own registries is the preferred way to address this, instead of implementing versioning support for git dependencies.
There's many bad things I say about golang, but "I wish this module system additionally required me to host a language-specific package repository" is not one of them.
If perforce is down, however, I'm starting a riot ;)
We also support checking the version of the git dep.
It's fetching the dep that's the problem. Git has no uniform protocol for talking about versions, especially when it comes to resolving SemVer ("you asked for 0.2.1 but I also have 0.2.5, here you go")
If you want go-style import resolution use a local git dep. That works fine. It's specifically when you want all the features of cargo's version resolution -- which git doesn't understand -- you need to use a custom registry.
Presumably, the `git` URL for dependencies, in `Cargo.toml`, can point to a local git repository. That should let you refer to a branch / commit of that repository, other than the one currently checked out (which is what using a `path` dependency would give you).
(The "local" comes from it being in-house but that's confusing)
And yes, this _can_ be added with some ad hoc scheme that requires you to use a certain kind of git tag, but that's not what people are asking for.
[1]: https://github.com/rust-lang/cargo/issues/1139#issuecomment-...
In general, this year of Rust will be about governance refactoring, finishing off long-desired features like the ones above, and general polish. There isn’t a lot of big plans for big new things coming anytime soon, more of finishing what we’ve started and improving what we have.
That also doesn’t change that const fn is stable today, so saying “it’s coming this year” muddies the waters a bit. You have to explicitly say “the capabilities of const fn will be expanded”, or you risk the wrong impression.
Oh, fantastic! I realize I'm probably in a very specific minority here, but I've been waiting on this one for literally years.
https://rust-lang.github.io/rfcs/1598-generic_associated_typ...
On a different level, a lot of work has been planned to address compiler performance, improve IDE integration, and provide better support of special workflows e.g. for embedded development, or for WASM and the like. Work is also still ongoing on writing high-quality reference documentation for the language, and moreover for a better understanding of how exactly unsafe code should be expected to work, which in turn will enable a more formal approach to the Rust language as a whole.