Purging proc from Rust
smallcultfollowing.com
smallcultfollowing.com
Why is Rust in such a rush to hit 1.0? Recent improvements have massively improved it, but I'm afraid it will lock too soon and suffer for it.
Rust holds some promise for me, but things like simple buffer manipulation, strings, and slices are ugly and torturous in Rust, compared to Go where they are a pleasure to work with.
You are barking up the wrong tree if you are waiting for Go-level simplicity, like the Rust folks have often said.
String would never allocate more than it does currently, but it would do it in less predictable situations which some people probably wouldn't like. However, it would basically allow people who don't care that much about short strings to completely eschew all the .as_slice()s and .to_string()s that are currently ubiquitous in any rust string handling.
That used to be the purpose of MaybeOwned, which was just replaced by CowString (a typedef of Cow to String and str).
On Cow, a deref returns an immutable slice (with no copy) so slice methods can be called directly on the CowString, `to_mut` copies the source data if necessary and returns a mutable ref, and `into_owned` copies the source data if necessary and returns it.
So if you don't really care what you get and whether it's going to be copied or whatever, ask for a CowString and go to town.
> if String could point to either &'static str or an owned buffer
There exists a copy-on-write smart pointer in the standard library that can be used for exactly this purpose: http://doc.rust-lang.org/std/borrow/enum.Cow.htmlSure, but I feel like Haskell is the same thing only more so. And the invariants you keep track of - does this function access the database? could this function error? which audit events might happen in this codepath? - are IMO more useful than in Rust, where you spend the same effort tracking memory ownership. Which, sure, if you need it better to have a compiler that can help you with it, but getting good performance without it is easier than many people seem to think.
The time for 1.0 is not now, IMO, but it is soon. At some point you just have to cross your fingers and launch, and learn to live with whatever mistakes you may have made. Experience has shown that the language is good enough in most respects, so even if they flub the last-minute things it won't be any worse than what any other brand-new language has had to live with.
http://blog.rust-lang.org/2014/09/15/Rust-1.0.html
The things you've mentioned as torturous are mostly sugar on-top of the already implemented primitives, and are even being worked on ([n..m] slice notation, to name one).
Almost: it will compile on all future Rust releases to the end of time (unless Rust wants to commit suicide). Languages cannot ever make breaking changes once they reach a stable version (unless they have relatively little adoption). This is even more crucial for "low level" languages like Rust, as they are often used for projects that are meant to last for decades, and are often chosen by programmers who want don't have the patience for this kind of thing.
Or nobody expects anything from them (see: PHP)
I think our final design (which might be charitably referred to as "unboxed closures 2.0") is actually really fantastic, and doesn't leave me with any of the lingering dissatisfied feelings that our previous designs did (at least, assuming that all the improved inference mentioned in the OP materializes). I look forward to playing around with them once they're more polished in a week or so.
I desperately hope that someday, when all the dust settles, someone writes an account of this and other long and winding paths Rust has taken through its evolution, so people in the future can get the benefit of this wisdom. An account of dead ends could make for fascinating reading.
The trick would be putting in just the right amount of detail. Enough so the reader can truly understand the reasoning behind why things worked (or didn't) without being so dense as to be unreadable.
http://haskell.cs.yale.edu/wp-content/uploads/2011/02/histor...
|&:|
|&mut:|
|:|
at declaration-site and an optional move
at use-site, in addition to obfuscating hashfn: |&String| -> uint
to either <F>(hashfn: F) where F : FnMut(&String) -> uint
// "FnMut(&String) -> uint" is "syntactic sugar for "<'a> FnMut<(&'a String,), uint>"
or hashfn: &mut FnMut(&String) -> uint
I really want to believe that this is a great success at the technical level, because from a UI point of view this is a disaster.From a UI perspective, I (and many others, including core team member Aaron Turon) have argued successfully that the vast majority of these details should be inferred from usage. So if you try to mutate something in a closure, the closure will adopt that requirement. If you want to capture a value by reference, you won't also be allowed to move the closure off of the stack.
In other words, the rules for closures will follow intuitively from the regular ownership rules, and you will never, in normal usage, have to be explicit about any of this.
This blog post was intended to explain in excruciating technical detail how it all works under the hood, and could have been clearer about the intended usage.
Finally, I'm actually not bothered about the type of a closure being written as `FnMut(blah)` instead of `|blah|`, because that syntax was always a bit line-noisy in type position anyway.
The bottom line is simply that closures in a low-level systems programming language present a daunting design challenge that is hard to appreciate until you've wrestled with the domain. There is no one-size-fits all here that does not result in compromises that make closures essentially useless for this niche. The best that we can do is reduce down to as few knobs as possible (Rust closures are still a bit less expressive than C++ lambdas) and lean on inference to have the compiler Do What I Mean.
It seems to me that we're restricting what a closure can do when it executes based on the type of closure that it is. Is this in the name of safety? If so, that seems like a good idea given Rust's goals. Right now it feels like a ton of mental overhead but I'll try and play around with it and see if I have an "A-ha!" moment.
Some of the blog post, mainly the part about using a wrapper function so the compiler can still inline monomorphized functions, makes me feel like this is a bit half-baked at the moment. I mean, the very nature of closures is that they give the programmer dynamic abilities.
I really enjoy Rust and the reason I enjoy Rust is the combination of low-level programming and safety. Maybe experiments like this are what gives us that. I hope I'm just confused right now.
edit: Oh, one benefit I see already is that since these are "unboxed" there won't be an allocation.
As for the wrapper function presented in the post, it's only to demonstrate that closures are implemented via traits and act just like any other trait in that they can be used to facilitate virtual dispatch (though IMO you shouldn't strive to use traits in this way if you can help it, given that Rust gives you many tools to help you prefer static dispatch).
Watching closures evolve in Rust over the past few years has actually been really interesting. We had an implementation that was "good" a few years ago, but was ultimately fundamentally inferior to the approach taken by C++ lambdas. The period since has been a fascinating exploration of ways to make closures safe, usable, and potentially zero-overhead in a language without garbage collection. For all I know it may be unprecedented.
I would say that such people may be broader than "Go users," but my "Rust for Rubyists" was one of the very first community tutorials for the language, and Cargo takes a lot of inspiration from Bundler, given that both were written by Yehuda. :)
Rust actually has quite a few Ruby/Python people, for exactly what you say:
> C scares me
This is basically what wycats said about himself in his GoGaruCo talk about Rust: https://www.youtube.com/watch?v=ySW6Yk_DerYTL;DR: People migrate from all kinds of places to all kinds of places. :)
Thanks for Rust for Rubyists, I remember reading it a while back. I should also thank you for the official Rust docs, which are a lot more robust now.
That would be the pot calling the kettle black.
> I'm a weekend wannabe systems programmer
> and was attracted to Rust from Ruby because C scares me
I myself was attracted from Javascript for the same reason, you're among friends. :) > this is where Go users laugh that Rust attracted a
> Rubyist instead of a C++ user
I don't think anyone's laughing at anybody. Different languages will appeal to different people, we don't need to begrudge anyone for that! > I'll have to research C++ lambdas some more but given
> the safety, usability and performance gains
Performance of Rust closures should be the exact same as C++ lambdas. Safety-wise, you get all the usual guarantees of Rust. Usability-wise, the main nicety of Rust closures over C++ lambdas is that Rust doesn't force you to specify a capture clause, and instead infers how to capture all of the closed-over variables based on context. I think that Rust may actually be strictly less powerful than C++ here (as C++ allows you to explicitly specify the capture mode for each and every upvar if you like), but we believe that you'll have all the power you need in practice. Whether or not this turns out to be true will have to be determined by experience.I love the fact that systems programming is becoming attractive again!
> this is where Go users laugh that Rust attracted a Rubyist instead of a C++ user
The members of the Rust community have very diverse backgrounds, so don't feel bad. We have systems programmers, pure FP folks, game devs, folks from the dynamic/web crowd... this is an encouraging thing! You will not be alone in coming from a dynamic language - some of our best contributors are also experienced Python, Ruby or Racket developers.
While the internals are probably going to stay the same (the traits), syntax sugar is still very much being thought about.
What can I do while they "rush" language to the 1.0 stable release?
I mean how to get the best from this situation if I want to be programming in Rust in future?
Many fundamental concepts in Rust, including arithmetic, comparisons, sendability, and smart pointers are formally traits (though the compiler may treat some of them specially, particularly arithmetic and comparisons).