
Announcing Rust 1.22 - steveklabnik
https://blog.rust-lang.org/2017/11/22/Rust-1.22.html
======
kibwen
Reminder that Rust's year-end sprint has one more month to go, and even though
we've gotten tons done there's still plenty of work to go around to anyone
with motivation and idle hands. :) See here for an overview:
[https://blog.rust-lang.org/2017/09/18/impl-future-for-
rust.h...](https://blog.rust-lang.org/2017/09/18/impl-future-for-rust.html)
and here for the most recent checkpoint summary: [https://internals.rust-
lang.org/t/impl-period-newsletter-3/6...](https://internals.rust-
lang.org/t/impl-period-newsletter-3/6185) We'd love your help!

------
margorczynski
Hey, is there any plan to add FP programming (functors, mondads, free monad,
etc.) to Rust as part of the language or some officialy supported library?

Also - any plans for Streaming?

I'm a big Scala user and fan (Haskell of course too) and would like to try out
Rust but I really don't see myself going back to structural/object oriented-
programming

~~~
whyever
There are already FP features and monads in Rust. What exactly do you want?

It is unlikely you will ever see non-zero cost abstractions in idiomatic Rust.

~~~
fmap
Can you link to some documentation about how monads work in rust? Based on the
sibling comment rust doesn't support higher-kinded types yet, so I'm
interested in how you would encode this in rust.

~~~
steveklabnik
Rust does not have HKT, and so we cannot write a generic Monad. Rust has many
_instances_ of Monad, though.

That said, at some point, we'll be getting ATC, which is equivalent to HKT in
many cases, but feels more Rusty.

~~~
ronjouch
Thanks :) . Nit: less TLAs, please.

\- HKT: Higher-Kinded Types

\- ATC: Alternative Type Constructors

~~~
steveklabnik
Yeah, sorry. It's "Associated" not "Alternative" by the way. A good reason to
spell them out ;)

------
akmittal
There was a PR recently which support wasm compilation without emcc. Does
anyone know when it is expected in stable?

[https://github.com/rust-lang/rust/pull/45905](https://github.com/rust-
lang/rust/pull/45905)

~~~
killercup
Good question! It was merged quite close to the release, so it's hard to guess
if it landed in beta already. So, let's have a look at [1]! And yep, it's in
the beta branch.

This means it's in 1.23, which'll be released in 6 weeks.

[1]: [https://github.com/rust-lang/rust/commits/beta](https://github.com/rust-
lang/rust/commits/beta)

~~~
MrBuddyCasino
Does that mean I will be able to compile to wasm via a simple cargo parameter?
If so - wow!

~~~
killercup
Yes, once [1] lands, you can add it with `rustup target add wasm32-unknown-
unknown` and then you can `cargo build --target=wasm32-unknown-unknown`.

You should note that it's not as simple as that, though. Depending on the
context you want to run WASM you might need to do additional steps. E.g., when
running this in a browser, you might not be able to use the std lib to spawn
threads just yet.

[1]: [https://github.com/rust-lang/rust/pull/46115](https://github.com/rust-
lang/rust/pull/46115)

------
mkl

      let mut x = 2;
      let y = &8;
      
      // this didn't work, but now does
      x += y;
    

Why is it desirable that that work? It seems like it will mask mistakes and
make types more confusing.

~~~
mark_edward
I agree. Some of the things done in the name of ergonomics just strike me as
wrong and/or possibly misleading for learners.

People who say Rust is hard to learn have always confused me. I learned
programming in this order: scheme, C, C++, Haskell, Rust. I believe that if
you go in another order it may make things more difficult, but some of these
difficulties are inherent. To me, a reference to a thing is inherently
different from the thing, and a systems language should make that clear. I
didn't even like auto-deref, I felt like there should be an operator similar
to

    
    
      thing->method()
    

in C++ that can be chained so that references and indirection would always be
syntactically clear and distinct, but the ergonomics on that won out.

~~~
coldtea
"People who say Rust is hard to learn have always confused me. I learned
programming in this order: (...)"

(proceeds to list a quite rare and outlier-ish learning sequence, and all in
non-scripting languages to boot).

Well, of course those people confused you. What you, who learned Scheme, C++
and Haskell before going to Rust, have in common with someone who only knows C
or Java or only got his start in some scripting languages, so as to be able to
relate with their "Rust is hard" experience?

~~~
mmstick
I personally went from Go (slightly mingling with it) -> Rust 1.0 (wrote my
first applications with it) and found it to be incredibly easy to learn in
comparison to C, C++, Java, and even Python and JavaScript. Everything's
pretty explicit and straightforward, and the API documentation and associated
resources are stellar.

------
drewm1980
I have no idea what that ? operator does from the summary or staring at the
usage example... Was more boilerplate necessary in the example before?

~~~
viraptor
It skips a block you'd need otherwise. Without it, you'd have to do something
like:

    
    
        fn try_option_some() -> Option<u8> {
          if let val = Some(1) {
            Some(val)
          } else {
            None
          }
        }
    

It's an early exit if the expression before is None/Error

~~~
Sharlin
There should really be a more real-world example, the current code (and your
alternative version) is just redundant and equivalent to

    
    
      fn try_option_some() -> Option<u8> {
          Some(1)
      }

~~~
lower
Suppose you have two functions

    
    
        fn f() -> Result<A, E>
        fn g() -> Result<B, E>
    

Then you can write

    
    
         fn h() -> Result<(A,B), E> {
            let x = f()?;
            let y = g()?;
            Ok((x, y))
         }
    

rather than having to do something like

    
    
        fn h() -> Result<(A,B), E> {
           match f() {
               Ok(x)  => {
                 match g() {
                   Ok(y)  => Ok((x,y)),
                   Err(e) => Err(e)
                 } 
               },
               Err(e) => Err(e),
           } 
         }
    

(written from memory, please excuse syntax errors)

What's new is that this also works with Option<A> now.

~~~
zZorgz
As others mentioned, it looks equivalent to using the try! macro (which I'm
not sure this is supposed to replace?)

Another sane alternative here is using _and_then_ , _map_ , etc.

Writing from memory too:

    
    
      fn h() -> Result<(A, B), E> {
        f().and_then(|x| g().map(|y| (x, y)))
      }
    

..which seems to be a different style of control flow to choose from. On one
hand, I suppose one may avoid using _and_then_ with code dealing with side
effects. On another hand, _?_ seems restricted to being used inside functions
that have to return a a single type (like Result) they operate on.

~~~
steveklabnik
? is explicitly a replacement for try!, yes.

> functions that have to return a single type

Well, all functions have to return a single type, though that type may be a
composite type, like a tuple.

Less pedantically, `?` lets you (well, will let you) unwrap values and convert
their error cases between each other. So once the next round of stabilization
happens, if you have a function that returns Results, you can mix ? on Options
and Results in the body, and vice versa. And it can be extended for other
types too. Basically, it's an early return "protocol" if you will.

~~~
zZorgz
By single type, I meant to hint not being able to mix ? on Options and Results
in the body, but good to know that's soon possible! Though you still can't,
eg, use `?` in _main()_

~~~
steveklabnik
That's coming as well!

~~~
zZorgz
Interesting. Looking at the proposal it seems specific to main() and not any
void returning function, by automatically picking an exit status. I suppose I
worry the construct has a lack of control (log diagnostics, exit status,
cleaning, etc) when bailing and can’t handle eg continue, break too.

~~~
steveklabnik
exit status and cleaning should be just fine, logging or something else would
need to not do it, yeah. continue and break would be weird outside of loops.

------
alfiedotwtf
Does anyone know why the last two lines in main() fail? AFAICS, v has the same
type as both functions.

    
    
        fn try_option_some() -> Option<u8> {
            let val = Some(1)?;
            Some(val)
        }
    
        fn try_option_none() -> Option<u8> {
            let val = None?;
            Some(val)
        }
    
        fn main() {
          assert_eq!(try_option_some(), Some(1));
          assert_eq!(try_option_none(), None);
      
          let v: Option<u8> = None;
          assert_eq!(v, Some(None));
        }
    

One other thing troubling me here - shouldn't try_option_none() return `None`
and not `Some(None)`?

Looking at the diff for the commit, there's now a NoneError? Is there any
documentation updates to look at how this works? Because AFAIK, now all
matches will have to explicitly be updated to check for NoneError, otherwise
they won't compile (since matches are not complete)?

~~~
steveklabnik
As the error says,

    
    
      = note: expected type `std::option::Option<u8>`
                 found type `std::option::Option<std::option::Option<_>>`
    

The return types of those functions are Option<u8>, but Some(None) is an
Option<Option<_>>.

> there's now a NoneError?

It's not stable yet.

> now all matches will have to explicitly be updated to check for NoneError

NoneError only comes into play when you have a function that returns Result,
but uses ? on an Option in the body. That code never compiled (and still
doesn't on stable until Try is stabilized, _and_ only if you have Result<T,
NoneError> as your return type _or_ some Err type that implements
From<NoneError>, which you also can't write until it's stable.

Does that help?

~~~
alfiedotwtf
Ah, awesome. Makes total sense now. Thanks!

------
jayflux
As these announcements get a lot of attention from non-rust devs it might be
worth linking to what ? Actually does somewhere in that.

~~~
wscott
"About a year ago, in Rust 1.13, we introduced the ?"

And that includes a link to the 1.13 announcement with a detailed explanation.

------
skywhopper
"Two recent compiler changes should speed up compiles in debug mode. We don’t
have any specific numbers to commit to with these changes, but as always,
compile times are very important to us, and we’re continuing to work on
improving them."

Can't imagine why compile times haven't been good in the past with this level
of detailed analysis.

~~~
steveklabnik
To be clear, I wrote the announcement, but don't work on compiler
optimizations. Those that do tend to have a better idea than me.

But beyond that, it's ultimately about what you promise. Say something sped up
compilation times 2x for most people, but slowed them 10x in a corner case. If
you promise the 2x, the people for who it slowed down will be (rightfully)
pretty mad.

None of these changes are as drastic as that, but still.

