top | item 24294960

Rust 1.46

391 points| pietroalbini | 5 years ago |blog.rust-lang.org

150 comments

order

est31|5 years ago

The most exciting component of this release is the const fn improvements. With loops and if available, you can now do non-trivial computation in const fn for the first time. It reduces the gap between Rust's const fn and C++'s constexpr to a large degree. Ultimately, the miri execution engine that this feature builds upon, supports a much larger set of features that even constexpr supports. It's been a project spanning years to get it merged into the compiler, used for const fn evaluation, and stabilize it's features (this part is far from over).

In addition to the linked examples, I have some code of my own which is made simpler due to this feature: https://github.com/RustAudio/ogg/commit/b79d65dced32342a5f93...

Previously, the table was present as an array literal in C-style, now I can remove it once I decide for the library to require the 1.46 compiler or later versions.

Link to the old/current generation code: https://github.com/RustAudio/ogg/blob/master/examples/crc32-...

tines|5 years ago

> supports a much larger set of features that even constexpr supports

This sounds promising. Can you give examples? I don't know Rust at all, and the reason I like C++ is its metaprogrammability.

marricks|5 years ago

I wonder why && and || are not allowed in const functions?

> All boolean operators except for && and || which are banned since they are short-circuiting.

I guess I'm missing something obvious but why does the short circuiting break const-ness?

sfvisser|5 years ago

I’m learning rust right now and there is a lot to like. Steady updates like this are also very motivating. The ecosystem feels very sane - especially compared to npm. Top notch Wasm support, cross compiling is a breeze.

That said, coming from a FP background (mostly Haskell/JS, now TS) Rust is... hard. I do understand the basic rules of the borrow checker, I do conceptually understand lifetimes, but actually using them is tricky.

Especially in a combinator world with lots of higher order functions/closures it’s often completely unclear who should own what. It often feels my library/dsl code needs to make ownerships decisions that actually depend on the usage.

Anyways, I guess this gets easier over time, right? Should I avoid using closures all over the place? Should my code look more like C and less like Haskell?

[edit] great answers all, providing useful context, thanks

ragnese|5 years ago

> Anyways, I guess this gets easier over time, right?

Yes.

> Should I avoid using closures all over the place?

Not necessarily.

> Should my code look more like C and less like Haskell?

Yes. Others sometimes don't like to hear this, but IMO, Rust is not at all functional. Passing functions around is not ergonomic (how many function types does Rust have again? Three?). Even making heavy use of Traits, especially generic ones, is difficult.

Rust is very much procedural. Java-style OOP doesn't work because of the borrowing/ownership. And FP style function composition doesn't work without Boxing everything. But then you'd need to be careful about reference cycles.

nemothekid|5 years ago

>the borrow checker, I do conceptually understand lifetimes, but actually using them is tricky.

I've been using Rust for a little over year, almost daily at work, and for several projects. I have a pretty good intuition about how the borrow checker works and what needs to be done to appease it. That said, I don't think I'm any closer to understanding lifetimes. I know conceptually how they are supposed to work (I need the reference to X to last as long as Y), but anytime I think I have a situation that could be made better with lifetimes, I can't seem to get the compiler to understand what I'm trying to do. On top of that very little of my code, and the code I read actually uses lifetimes.

thenewwazoo|5 years ago

I don't have time for an exhaustive answer, so I'll give you some rules of thumb when using Functional-style combinators:

* If you need to keep unchanged the input, you must either use a reference-to (.iter()) or copy-of (.iter().cloned()) of each item

* If you don't need the input ever again, you should move the items (.into_iter())

These rules follow for each step of the chain.

I very very often write very Functional code in Rust and I find it natural and easier to reason about than imperative-style code. The example I could find the fastest: https://github.com/thenewwazoo/aoc2019/blob/master/src/day10...

Edit: another example (this one uses types that are Copy so the copies are implicit) https://github.com/thenewwazoo/cryptopals/blob/master/src/tr...

Another edit: I am not a Functional programmer, and have never known Haskell or any Lisp. Erlang is as close as I've ever gotten. I've found Rust to be a fantastic language for writing Functionally.

vmchale|5 years ago

> I do understand the basic rules of the borrow checker

It ends up being doable. I dabbled in ATS, developed Stockholm syndrome, and now Rust ain't too bad.

Higher-order functions are difficult in Rust or with linear/affine types in general. Haven't looked at what Rust does recently.

> Should I avoid using closures all over the place? Should my code look more like C and less like Haskell?

When in Rome do as the Romans :)

Anyway, some fun imperative programming stuff you can do in Rust that is fickle in Haskell (or OCaml/Standard ML).

Fiahil|5 years ago

Ah, if you’re making dsl code or functional combinators, you usually want to ‘move’ your values instead of ‘borrowing’ them.

example:

fn add(mut self) -> Self { self }

fn add(self) -> Self { self }

instead of:

fn add(&mut self) {}

fn add(&self) {}

With this, you will be able to ‘store’ closures easily and apply them later. No more fighting with the borrow checker over where to borrow as mut or not. You will also avoid a few copies.

stevencorona|5 years ago

This echoes my experience with learning Rust over the past few weeks (coming from Elixir).

There is a lot to like, understand lifetimes conceptually, but it's hard.

Shorel|5 years ago

Yep. I made my first Rust script last week and the amount of care required is similar to C++.

It is definitely not easier compared to C++, contrasting with D, which is easier than C++.

However, the program worked correctly at the first try, which I guess it is also a consequence of the Rust model.

zozbot234|5 years ago

> The ecosystem feels very sane [] compared to npm

Now that's damning with faint praise.

stjohnswarts|5 years ago

Sometimes you will be annoyed by changes I guarantee it BUT since 1.0 that's decreased a lot and compared to npm it's night and day. You'll think you're dealing with C in relative terms of stability if npm is your baseline :D

kumarvvr|5 years ago

So, I want to learn Rust. I am a C# / Python programmer, experienced.

Are there any particular set of problems that I can solve systematically, so that I can learn all the features of Rust?

apendleton|5 years ago

Meta-answer: my default when picking up a new language is usually to learn just enough to be able to start writing code, and then learn new things piecemeal as necessary to solve whatever thing I'm working on, and it sounds like you're hoping to do something like that here.

I found that approach for Rust in particular to not work well at all, and have colleagues who've reported the same. There are some fairly complicated, fundamental concepts that are unique to Rust that I think need to be tackled before you can really do much of anything (mostly borrowing and lifetimes), and that's not immediately obvious from starter programs -- because of lifetime elision, some early programs can look deceptively familiar, but there's a bunch of barely-hidden complexity there, and as soon as you start to stray from the tutorial path, you'll run headfirst into a wall of compiler errors that you're not yet equipped to understand. For Rust I'd highly recommend just reading a book cover to cover first (either TRPL or the O'Reilly one), and then starting to write code.

jandrese|5 years ago

One thing I'd be wary of is Googling error messages and taking answers from Stack Exchange. Rust has mutated (heh) a fair bit over the years and many SE answers to noob problems are obsolete and sometimes incorrect. At the very least check the datestamp on any answer and be wary of anything more than a year or two old. This goes double if the answer has some extremely awkward looking syntax with lots of modifiers and underscores sprinkled throughout. There's probably a better way to do it now, or an alternative solution that works better. Or maybe you're just trying to do something that Rust makes hard, like concurrent processing on a shared data structure.

The manual is safer even though it's harder to find your exact problem and solution, especially when you're just starting out.

xvedejas|5 years ago

Trying to implement anything in Rust will set you up for a crash-course. Even the simplest non-trivial programs will introduce you to the Rust borrow checker, a major feature absent in C# / Python.

brundolf|5 years ago

Once you've learned the basics (plenty of links in the siblings, including the official Rust Book), this is a key (and entertaining!) unofficial resource that really hammered home for me the ways that Rust is different from the C family when it comes to working with references: https://rust-unofficial.github.io/too-many-lists/

It also taught me about Boxes and Rc's, which are essential for certain kinds of things, and which I don't remember being covered in the main Rust Book at all

BiosElement|5 years ago

You might check out https://exercism.io/tracks/rust . Some are a little heavy in the math department but personally I've always found test drive learning useful when learning a new language thanks to instant feedback.

datanecdote|5 years ago

I am in similar boat. Python centric data scientist. Very tempted to try to learn Rust so I can accelerate certain ETL tasks.

Question for Rust experts: On what ETL tasks would you expect Rust to outperform Numpy, Numba, and Cython? What are the characteristics of a workload that sees order-of-magnitude speed ups from switching to Rust?

gchamonlive|5 years ago

I like to implement something I have already done before. In my case, the ID3 algorithm has a nice balance of challenge, experience and documentation available. You could try to write it for a specific case, where you structure your data, and then apply it to a generic case.

smabie|5 years ago

Write a chip8 emulator in Rust.

thomasahle|5 years ago

If anyone wants to know more about const fns, see https://doc.rust-lang.org/reference/items/functions.html#con...

It is the Rust way of specifying a function as being _pure_. In other words the output is dependent only on the function arguments, and not on any external state.

This means they can be evaluated at compile time. I suppose in the future, it could also allow better compiler optimizations.

ko27|5 years ago

Never worked with Rust, but I am pretty sure that having a function be pure is not enough to evaluate it at compile time.

the_duke|5 years ago

Rust has no notion of purity. This would require something like an effect system.

const functions can't directly do any IO or even allocation - at the moment.

But this can be easily circumvented, eg by using a proc macro that does IO.

Sidenote: even in Haskell the function signature doesn't guarantee purity, due to unsafePerformIO.

pitterpatter|5 years ago

An interesting history note: Rust used to have an effects system which included actually being able to annotate a function as pure.

kevinastone|5 years ago

Glad to see `Option::zip` stabilized. I tend to write such a helper in many of my projects to collect optional variables together when they're coupled. Really improves the ergonomics doing more railroad-style programming.

borgel|5 years ago

Do you have an example? I'm having trouble understanding how zip would be used in practice.

LEARAX|5 years ago

The quality of life improvements to cargo look very nice, and I feel that rust wouldn't be remotely as successful without such a tool. I'm very glad I won't have to be manually picking target directories out of my borg backups anymore when I'm running out of disk space.

cordite|5 years ago

These const fn’s are cool, but won’t this also lead to long compile times down the road?

steveklabnik|5 years ago

Yes, any time you move computation to compile time, it makes the compile time take longer. As always it is a tradeoff.

One thing that people may not realize, especially now that we have loop. You may expect this to hang the compiler:

    const fn forever() -> ! {
        loop {
            
        } 
    }
    
    static FOO: u32 = forever();
But it won't:

    error[E0080]: could not evaluate static initializer
     --> src/lib.rs:2:5
      |
    2 | /     loop {
    3 | |         
    4 | |     } 
      | |     ^
      | |     |
      | |_____exceeded interpreter step limit (see `#[const_eval_limit]`)
      |       inside `forever` at src/lib.rs:2:5
This does place an upper limit on any given const fn.

Verdex|5 years ago

Yeah, but only if you use them to compute significant items during compilation.

The upside of course is that any computation you compute at compile time is a computation that you don't compute at runtime. For some applications this trade off is definitely worth the cost of admission.

At the end of the day it's a trade off that will have to be made in light of the scenario it's being used in. Being able to make that decision is a good thing.

orthecreedence|5 years ago

Awesome! Any idea when relative links will be available in rustdoc? Seems like it's just on the edge of stabilizing (https://github.com/rust-lang/rust/pull/74430) but I'm curious how long it takes to see in a release after this happens.

steveklabnik|5 years ago

There can be fuzziness here depending on exactly when it lands, but generally, if something lands in nightly, it'll be in stable two releases after the current stable.

fmakunbound|5 years ago

> if, if let, and match

> while, while let, and loop

> the && and || operators

Common Lisp user here. Why just that? How come you can’t have the entire language as well as all your language customizations available at compile time for evaluation?

pthariensflame|5 years ago

You can! Just not through `const fn`. Rust has macros, which at their limit are capable of running arbitrary Rust code that manipulates syntax and communicates with the compilation process, just like in a good old Lisp.

Why isn’t `const fn` like this too? One word answer: determinism. Rust takes type/memory/access/temporal safety very seriously, and consequentially you can’t use anything in a `const fn` that isn’t fully deterministic and doesn’t depend in any way on platform-specific behavior. This includes, for example, any floating-point computation, or any random number generation, or any form of I/O, or handling file paths in an OS-specific way, or certain kinds of memory allocation. The span of things possible in `const fn`s has been expanding over time, and will in the nearish future largely overtake C++’s direct counterpart of it (`constexpr` functions) in capability. But some things will intentionally never be possible in `const fn`s, for the reasons given above.

echelon|5 years ago

`const fn` improvements are amazing!

I can't wait for when we'll be able to `const fn` all the things. Regex, expensive constants that feel as though they should be literals, etc.

scott31|5 years ago

[deleted]

kibwen|5 years ago

> entire rust team was recently fired from Mozilla

This is completely incorrect, verging on FUD. Mozilla had very few people working full-time on Rust; of the people who were laid off in the recent wave, the ones working on projects adjacent to Rust were working on Servo or WASM-related codebases. In particular, the person at Mozilla who was most central to Rust development, Niko Matsakis, is still employed there and still working full-time on Rust.

AsyncAwait|5 years ago

They're moving to a Rust Foundation with corporate sponsorship model. I think Rust will be fine, even Amazon expressed interest in sponsoring development.