1.26 has impl Trait, which is one of those things that really makes your life easier as a Rust developer. I've been using beta already with the new API I'm building just to get that feature, now on stable right before I'm actually thinking of deploying the API. Nice.
Will rust users get a break someday?
That being said, we'll be adding new language features as they fix pain points for users and fit in with the rest of the language; when that's not true, we won't move so quickly. Rust is still fairly young, there's a lot to do!
I also need to go and find all of my impl Trait TODO comments and get to work on cleaning those up! What a good day.
I should also say that while I haven't read the second edition of the book yet I am excited to have some new Rust-related content to read. The first edition of the book was a really eye-opening learning experience for me (both about computers and Rust and also about how to build a community and prioritize teaching) and I can only imagine what an improvement on that is like.
As always, happy to answer questions, provide context, etc.
fn foo(x: i32) -> Box<Iterator<Item = i32>> {
let iter = vec![1, 2, 3]
.into_iter()
.map(|x| x + 1);
if x % 2 == 0 {
Box::new(iter.filter(|x| x % 2 == 0))
} else {
Box::new(iter)
}
}
Why is it that I can't return `impl Iterator<Item = i32>`? Doesn't the `Filter` type implement `Iterator` for the same associated type?By contrast, if I returned a boxed trait, then calling the trait method requires a dynamic lookup to find the method on the boxed object, and then jumping to that function (dynamic dispatch). In this example, `iter.map(..)` and `iter.filter(..)` return two different implementations of the Iterator trait, so dynamic dispatch is required.
In general, if your function returns multiple possible implementations of a given trait, then the compiler cannot know where the trait methods will be statically, so it is impossible to do static dispatch. Since impl Trait wants to guarantee static dispatch, it requires that only one possible implementation of the trait be returned.
There is some discussion about it possibly being sugar for an anonymous enum in the future, but that’s not what it is right now.
In Rust (most languages), by default the compiler needs to set aside space on the stack for each return value. So it needs a constantly known size (and shape) to create the slot on the stack. You need to flip to dynamic dispatch, ie a pointer to an object (Java's default), that will be placed on the stack as a reference to the unknown size/shape of the thing at the end of the pointer when the size/shape is unknown. A pointer always has a constant size on the stack.
In this example, `impl Trait` is just saying I want the compiler to figure out the size/shape of the thing being returned for me, and allocate that to the stack at the call site of the function. What this means is that even with `impl Trait` you must return a thing that has the same size/shape.
Steve's answer mentions a common pattern used to create constant size/shape by using an enum for the wrapper type to return two different types on the stack from the function. The only other option is to put something with unknown size behind a pointer, ie Box<Trait> or &Trait, and thus pay the expense of dynamic dispatch.
Is there anywhere I can get a quick recap of major features Rust is planning to eventually maybe implement, and their state? I mean major features like NLL, impl trait, etc.
IIRC: NLL are nightly already, const generics in planning stage, and what happened to CTFE? For us not in the know, a sneak peek on what's coming/being discussed is very exciting, but browsing the issue/RFC tracker is sometimes a PITA and it's hard to keep up to date, especially after getting used to the workarounds.
I mean, just yesterday I had to do some weird stuff to a for loop in order to iterate over all u8s in a cleanish way.
Lovely, lovely work. I'm especially excited to see how clever the ref/ref-mut `match` inferring is. If it's reliable, that's gonna remove quite a bit of friction for newcomers. So cool!
Being able to return anonymous trait impls from inside functions could eliminate a lot of what seems like boilerplate structs/impls from Rust code. As an example, the code in futures-util that adds combinators to a Future defines a type (Then, Fuse, Map, etc) for each combinator function. With those functions now able to use 'impl Future<...>' as the return type, being able to actually type 'return impl Future<...>' could make code like that a lot less cluttered.
While I'm sure it won't mess anyone up, the range for the i128 is hard to interpret. It looks like -xxxxx - xxxxxx but with the extreme number of digits it looks like two negative numbers or a subtraction problem.
[edit: u128 -> i128]
Is the non-lexical lifetime improvements work locked to a particular release yet?
Also, now that the async/await RFC has been merged, is its implementation in nightly or stable going to be squeezed in for the 2018 roadmap plans?
As for non-lexical lifetimes, there's lots that's been implemented but much of it is still experimental; follow Niko Matsakis' blog series at http://smallcultfollowing.com/babysteps/blog/2018/04/27/an-a... to stay up to date with what's happening.
Question: Is there any way to preview what the book's typesetting looks like, since there's praise in the release note?
It's totally fine to decide to make the trade off, but it's just frustrating to not have the downside acknowledged.
Cause it sounds like a strong commitment here.
All that said, Rust definitely errs on the side of preferring to put things in 3rd party crates instead of stdlib, even for things that are very common to put in std for other languages (e.g. random number generation).
- HTTP client
- CSV parser/generator
I know Hyper and rust-csv are popular. But having an stdlib that's much more feature complete would be great.
Which charity/charities?
Source: I've volunteered for them in the past as an instructor.
impl Trait is HUGE. And there's tons of other stuff too. This must be the biggest single release since 1.0.
Out of curiosity, why was the (or an alternative) choice not to make the compiler understand that the 0..256 was not inclusive, and somehow correct the literal value to do what's intended? Would that have been unusually complicated or?
Edit: Overall, still an amazing release, this was just the bit I'm curious about :) Great work by the whole Rust team/community
[1] https://groups.google.com/forum/#!msg/golang-nuts/7J8FY07dkW...
The community is amazing, and I actually understand all these features that were released I've run into about half of the issues they fix already.
Rust is coming along very very nicely.
I haven't used it enough to have much more to say -- I've found everything pretty ergonomic so far (especially for a C/C++-tier language), I was most frequently confused when thinking of the most idiomatic way of doing something, but that's remedied by reading more (the rust book first/second edition, the rust cookbook). This should change over the coming weeks.
This isn't a particularly useful comment, but I chose Rust over Common Lisp recently for this new project, and I've found the std library's google-ability to be excellent for rust -- very few pages about steel have come up so far ("result rust" in DDG brings up rustlang related links). When I explored CL, I did not find that to be the case, but maybe I just didn't know where to look -- hyperspec is close but it is a terrible document to navigate through, and the 90s graphics didn't help (though they were nostalgic). Rust documentation is very often concise, well structured, and passably beautiful. I was also pleased with the Abstract Data Type solution in rust -- tagged unions. Some code:
#[derive(Debug)]
pub enum ConfigLoadError {
EmptyFilePath,
IO(IOError),
TomlParse(TomlError)
}
The abstraction enabled here is just right for me, super similar to code that I'd write in Haskell, and helps me abstract over errors thrown by utility libraries (in this case `toml-rs`).Keep it up Rust team. The language is incredible! Really my only daily complaint is IDE support is still abysmally slow, in both IntelliJ and VSCode.
This and not being able to do paramterized array sizes for things like SoA, AoSoA where the two things that I feel like were missing from Rust. Really happy to see the first landing(and I understand work is going on for the second).
But I needed this yesterday!
Seriously though, this is an amazing release and so much stuff in here I've been looking forward to for ages. impl Trait is going to change the way I write Rust.
Personally, not a fan of the match change. But then I was already not a fan of autoderef in method calls.
let example: (String, String, String) = ("ref".to_string(), "to".to_string(), "ref".to_string());
let example: (&str, &str, &str) = match &example {
(ref1, to, ref2) => (ref1, to, ref2),
};
Which might look confusing to people, it's converting from &(1,2) to (&1,&2)... but it's still type safe. Besides something like this, is there another reason to be worried about it?https://play.rust-lang.org/?gist=e37f9b31cc5e5c7b9d19c6b0a4c...
For field access/method calls, autoderef is a bigger convenience because we don't have the C++ -> operator, but I think I'd have preferred a syntax change here over the current behavior.
fn foo(s: &[char]) {
match s {
['a', 'b'] => (),
[.. 'b', 'c'] => (),
_ => (),
}
} some_collection.windows(2).filter(|[a,b]|a==b).map(|[a, _] |a).collect();
Turns out the compiler rejects that with a "refutable pattern" error, because the args part of the filter/map closures do not handle the situation where the slice could be empty, which AFAIK can not occur when using windows/chunks/...Maybe there has to be some special case handling for this pattern to be valid?
EDIT: I didn't read closely enough. Only a single type is allowed, so the traditional existential type construct ("trait objects") are still needed.
Would the book be updated as new features are added to Rust? I see some useful things being incorporated slowly into the language...
Work on the "2018 edition", which is the next version after "second edition", is just starting. It will be getting updates as new stuff lands, though there may be a bit of lag. In general, docs are going to be a bit weird up to the Rust 2018 release; it's all coming together, but slower at first, faster at the end.
(This means that, as of right this moment, there aren't great docs for impl Trait. I'm working on them right now.)
By the way, how is the progress of supporting XDG base directory spec for rustc and cargo?
One iterator simply returns the value and increments, and the other needs to apply the filter first and potentially advance several times.
Rust on the other hand is targeted more towards developers that want C-like low-level control along with safety against shooting themselves in the foot.
The former audience is probably larger than the latter. But popularity isn't everything (JavaScript wins that contest ;)). The important thing is Rust is doing an amazing job in an area that hasn't seen much love.
Rust hits the sweet spot of not being a pain in my ass all the time.
Yep, checking in. I want to write libraries that work on Windows, Linux, OSx, iOS, and Android that expose a C api but without having to write any C.
I know a bit of C, but not enough to feel like I can effectively use it to build the things I can build with Rust.
It takes a long time for a language to build momentum and a user base. Python was just starting to get popular when I graduated from college in 2005, and it was already 16 years old at the time.
Most apps out there are extremely serviceable with a language environment that runs up to 2x slower than what is possible with Rust. Youtube, edX, reddit, coursera all run on python, Facebook on PHP/Javascript, WhatsApp on Erlang.
In exchange for ceding low-level control, these languages provide a frictionless approach to evolving a system. You get dynamic features that are simply wonderful for creativity. Javascript is a blot on the landscape, but look at the effortlessness of d3.js.
GC is wonderful and does not gets in the way for most apps (from mobile to enterprise). Any time spent thinking about lifetimes sucks the fun out of coding. Lifetimes are fantastic for concurrent programming, no doubt, but there are simple patterns in Go that work well in practice.
Lightweight threads remove another point of friction; they allow you to model the concurrency inherent in a problem without much trouble. I'd prefer Go to get more of Erlang's failure handling and signal delivery mechanisms.
Go is a middling language, but its libraries and ecosystem are solid and have a coherent feel. They work out of the box without having to consult StackOverflow a zillion times.
The language I would love to have is Swift retrofitted with Erlang's process system.
Rust improvements like NLL will hopefully reduce the costs. I think we will discover more ways to leverage the benefits, over time. However, I also think it might be interesting to let people opt into a Rust dialect that hides lifetime issues, e.g. using a lot of implicit Rcs and (Ref)Cells.
Go also hits the sweet spot for CLI apps, in my opinion. The error handling is obtrusive and annoying otherwise, but for command line apps where you're just aborting whenever you hit any kind of snag, it's not a significant pain point.
I think this is a pretty major piece as well. Go was introduced many years earlier, backed by Google marketing and had strong HTTP services as a day one feature; it was designed for probably the most popular use case by perhaps the most influential fount of new tech. Given all that has Go really done all that well? Has it gone much beyond network services and a couple other niches (Docker/K8s etc?) It's not really displacing C/C++ in 'systems' use cases. It's not a go-to language for Machine Learning. The runtime+GC obviates most embedded work. You don't see any meaningful uptake of Go among Google's peers; Apple, Microsoft, Oracle, etc. I wonder just how important Go really is.