It took me longer than 4 days (almost two weeks) to just read the rust book (part time), so yes you're not going to get from 0 to 100 in just four days. If that's your benchmark, how fast you can get going, then you're right Rust isn't for you. But nobody would expect anyone to get up to speed with C++ in just four days.
Rust is a systems programming language with a focus on security and performance, not a play toy for people looking to write small scripts.
IMO this tone or slights against Go will hardly endear Rust to people. Rust's superiority should stands on its own. Not just you I have seen this sentiment many times by Rust enthusiasts on reddit and elsewhere.
Go already has successful companies like Docker, CoreOS etc literally built using Go. There are 100s of companies using Go productively. Very large software like kubernetes, docker, etcd are written in Go and they are not toy scripts.
For some people who've spent the time with it, Rust is a godsend, but that does not mean that by believing so they implicitly hate Go in anyway.
Go clearly has a lot of people who love it as much as people who love Rust, and because they overlap, there will constantly be a conversation of which language to pick for cases where it looks like both could be used. As such, the learning curve for Rust will always be an impediment, to its adoption, which is sad, b/c in all my experience it's the only language that I've used which inherently answers every core issue or fundamental bug that I've encountered in my career. This is why I'm really excited that the Rust core development team has decided to focus on development experience heavily this year.
While Go's frustration often comes from debugging sloppy concurrent code, the frustration with Rust is often about having your code to compile. But once it compiles, it runs beautifully. Some prefer the former, I personally prefer the latter. Also, I think the argument of increased productivity with Go should not be the main argument, because the time you save writing a large program, you will probably lose trying to debug a deadlock (which could still happen in Rust but harder to make happen) or a random data race that the race detector couldn't catch (or in a vendored library).
If I had to define the experience with both languages, Go is the instant gratification option, you feel productive quickly, the language is easy to learn with a forgiving syntax sometimes at the expense of correctness. Rust is the delayed gratification option, frustrating at times, very hard to learn and master but offering strong safety guarantees with an elegant syntax (which is a personal opinion).
Also it's a controversial topic in the Go community but the lack of generics...
Rust has its downsides too, for example the slow compile times or the lack of maintained libraries for some core functionalities but overall, programming with Rust is a much more enjoyable experience once you start getting ahead the learning curve.
One last thing: It is hopeless trying to learn Rust in four days without very good resources/books. I recommend "Programming Rust" from OReilly if you really want to dig into the language. It's incomplete at the time of writing but still one of the most useful resource out there (with the free Rust ebook). My knowledge of Rust dramatically increased after reading it and I felt much more confident writing larger programs.
This sentiment (or slight) is the same as always said of C and C++, that they are used to make real things (systems and infrastructure, foundations), and the sentiment (and slight) is there because there's a lot of truth to it.
Which language was used to write our *nixes, windows, the biggest web servers (apache, nginx, IIS), haproxy, mysql, postgresql, oracle db, etc, etc? C/C++, of course. What else?
Docker is just a front end/abstraction layer for the features already in the Linux kernel (written in C). You can write, what's essentially just automation tools, like this in any language.
I don't think what you write in this post is a testament to any strength of Go. If currently there exist a testament to its strength it must just be the fact that it's used; adoption rate/popularity, although I have not seen the numbers.
That's actually a perfect example of "systems programming", in the true sense of the phrase. And it is done in Go, because it can be done in Go.
Docker and CoreOS are not really successful companies...it's hard to say if any of the companies in that space will be successful.
That's actually a reasonable beginner's use for Rust though [0]. It's easy to do and will expose you to enough of the language to be a learning experience, but not so much that you could get badly stuck. And the benefit is that it's a lot easier to share binaries than it is to share scripts that rely on a particular interpreter being installed.
[0] http://www.chriskrycho.com/2016/using-rust-for-scripting.htm...
I do wish there was an actual Rust interpreter.
(In my case, I wanted to print out the name of the executable. Having to convert OsStr to something I can print, I understand - the filesystem encoding can be different from the console encoding. But it took longer than it should to find a path between the two.)
I never had to print an osstr yet but it seems fairly straightforward when looking at the docs? There are three obvious functions one could use, each for different use cases: https://doc.rust-lang.org/std/ffi/struct.OsString.html
os_string.to_str() // returns Option<String>
os_string.to_string_lossy() // returns Cow<String>, replacing illegal characters
os_string.into_string() // returns Result<String, OsString> - String if the data is valid, stays OsString for error handling otherwiseI'd be better doing it in another language, I'm doing it mainly to keep getting familiarity with the language.
Do you need to read a really good Go book to be productive in Go? If not, I think the OP's point stands, no?
There are certain languages which are different enough from traditional semantics to need an explanation. While others are similar enough to be "obvious" if you've used a semantically similar language before.
To give a specific example, Powershell. It is semantically a very different scripting language from almost anything else in the market. Extremely well designed and powerful, but you'll want to sit down and read an actual book on how it works to get to handle on it because you won't have the mental map already to do so.
Overall this is why the programming language market is so predisposed for new languages looking and feeling like old languages. People just aren't comfortable stepping too far outside of their comfort zone semantically (even if they'll happily do so for a few new language features and libraries).
One of the best things about Rust is that it's a paradigm change, it takes time to get your mind around it but it is worth it if the language fits your use case.
I'm not sure that's fair. It seems more likely that people who choose "boring" languages do so because they have things to build, and want to pick a language with a good risk/reward value. Not out of some academic interest or comfort calculation.
On the other hand, if someone can pick up Go and produce a side project with two weekends worth of messing around, they're much more likely to be supportive of the language.
Obviously this isn't ideal, but I don't know how you'd fix the problem.
Secondly, as per the Rolling Stones, you can't always get what you want.
It's strange the short term focus that is accepted in what are nominally professionals.
> Rust is a systems programming language with a focus on security and performance, not a play toy for people looking to write small scripts.
If you're suggesting Go is a play toy, you're wrong.
My understanding is that the rust team has put 2 priorities ahead of everything else: zero cost abstraction and safety. Given those constraints they've done a fantastic job in the area of ergonomics, but I don't know if it will ever be easy. Maybe rust is as easy to use as it can be.
> HashMap<T: Hash+Eq, u64>
I can take a wild guess that T is a generic type defined on either the method, struct or impl in which this HashMap is declared. It's on the method/struct/impl. You don't necessarily need the type bound on the struct, but you do on the impl declaration:
struct MyStruct<T: Hash+Eq> { map: HashMap<T, u64> }
impl<T: Hash+Eq> MyStruct<T> { pub fn insert_something(&mut self, my_key: T, my_int: u64) { self.map.insert(my_key, my_int); } }
try it here: https://is.gd/RwUpQx
Honestly I feel like peoples biggest issue with Rust is that they're trying to write things in Rust that don't actually need Rust. They want the ease of use that you get with a garbage collected language and then get annoyed when Rust forces them to worry about allocations and cleaning up after themselves. C++ should have the same issue but its been around long enough that most of those details have safely been wrapped behind STL and other abstractions to the point where most people don't need to worry about them. Perhaps in time Rust will reach that point as well and everyone will be using the equivalent of Boost that abstracts worrying about whether something is a Box<ARC<Foo>> behind a nonthreatening layer of macros.
To your other point, it saddens me that Rust isn't well-suited to higher level applications. You need very strict performance requirements before it makes sense to pick Rust over Go (you can squeeze a lot of performance out of Go, and even optimizing Go is friendlier than writing naive Rust IMHO).
I've written a decent bit of Go, and I understand why a lot of people like it, but I don't think it's inherently better for application development.
I want to be comparatively productive in Rust, I just never seem to get there because of the huge volume of decisions (even if the decisions are mostly easy) that need to be made for even straightforward code units. I think what I really want is Rust lite, or Go with generics and abstract data types.
None of that is to make a value judgement, just an observation; but I would still argue that the language can be used in a highly productive manner. Nonetheless, it's perfectly reasonable to argue it's not worth adapting to it, especially if Go is already solving your problems and keeping you productive. I switched because Go's design doesn't seem to fit me very well, and I continually tripped on issues that I don't encounter in Rust. (So yes, perhaps I'm quite odd.)
I do understand the want for a Rust-lite; the thought has crossed my mind more than once. So far, Swift seems closest in many ways and may get close once the Linux/cross-platform story starts looking good.
I'm not saying Rust is easy, but I have also a long Scala and some Haskell background which made it easier to learn Rust. For me the hardest part was that I've never really wrote any proper C++ or C, although I could read them quite good. Refereneces and RAII caused some gray hairs, the type system not that much.
Well this is true for all languages! You need to think hard for every decision you take with languages like Ruby or Python. Things like how will this look like after a year, will the junior developer be able to extend it, will there be data races and so on.
Rust just enforces you to do this. And it makes life much easier when you don't need to worry about some silly mistakes you made, because the compiler will catch them.
That is unfortunately not true enough.
Rust has a brilliant solution for some really burdensome issues that C++ developers have. A lot of C++ code tends to make assumptions about ownership and lifetimes that are not formally spelled out anywhere in the code. It's all over the place, it increases cognitive load, it makes the code brittle and less modular than it could be. Rust fixes that without negatively affecting performance whereas all C++ workarounds like shared_ptr and defensive copying are incomplete and/or have a negative performance impact.
But Rust also insists on enforcing its ownership rules between variables within the local scope where it doesn't help much and feels needlessly restrictive and convoluted. I can't say I know Rust well enough to tell whether working under these restrictions can become second nature and stop being a burden.
Also, users of garbage collected languages don't have many of the ownership and lifetime issues that C++ developers are forced to think about. Especially where objects are immutable, ownership is not a concern at all.
So I think Rust is an answer to one question: How can I have detailed control over resources like in C++ without inheriting all the hazards of C++ as well.
No, Go does not have that distinction. This is even in the Go FAQ: https://golang.org/doc/faq#stack_or_heap
> When possible, the Go compilers will allocate variables that are local to a function in that function's stack frame. However, if the compiler cannot prove that the variable is not referenced after the function returns, then the compiler must allocate the variable on the garbage-collected heap to avoid dangling pointer errors.
As you can see, Go uses both the stack and the heap; however, unlike Rust, it doesn't require users to know where their variables live to write correct programs.
Once you take the address and escape analysis is performed, you've got no way to easily reason about what's on the stack vs. what's on the heap, without delving into the gory implementation details which may be changed in future versions.
Since Go isn't C++ and doesn't have a huge and complicated standard that guarantees compiler optimizations, you can't really reason about what's going on.
This is essentially the same situation as Java, although the Hotspot JVM's escape analysis is probably less 'basic'.
This is not to say that Rust is better than Go in every way, but performance is far from the only facet when I compare the two.
What do you base this belief on? I'm very comfortable with C and assembly. I am very certain I understand the difference between stack and heap allocated data, but I've found lots of other hurdles in learning Rust.
One difficult aspect of Rust relative to Go must surely be generics and trait bounds. This is something it shares with Haskell and Scala. For people coming from those languages (like myself) the stack/heap thing is the most salient.
> One difficult aspect of Rust relative to Go must surely be generics and trait bounds.
Conceptually this isn't bad at all. I understand the value and mechanism of specifying the required traits for types to a generic function. However, I just posted an example elsewhere in this discussion where there simply isn't a trait for the method I want to call. That was certainly a hurdle for me, and the workaround wasn't satisfying.
I mostly understand the semantics of borrowing mutable vs read-only references, and I'm pretty sure I understand the purpose and value of the concept. However, specifying lifetimes is completely different than any other language I've ever used, and I've used a couple dozen languages over several decades in my career. I haven't gotten past that hurdle yet.
> the stack/heap thing is the most salient.
I'll stick with my statement that I understand the stack and heap well enough (from a C or C++ point of view), but composing Box, Cell, Ref, RefCell, and friends is a non-trivial hurdle.
Depending on your background there probably are various hurdles to overcome in learning Rust, I'm not discounting that, but the most uniquely Rust one is the stack vs. heap issue, particularly since that combined with issues around shared state are the sources of most of the headaches you'll run into when fighting with the borrow checker. Pretty much every other feature of Rust is similar enough to another language that if you have experience elsewhere you won't find it particular troublesome. References are easy to understand if you know C/C++ (and to a lesser extent C#). The type system is easy to understand if you know Haskell or Scala (and to a lesser extent JavaScript/Python). The generics system is pretty much the same as Java, C#, Haskell, Scala, or C++ (and probably others).
Rust IS a complex language, but it also provides a unique feature set and has some fairly unique goals. IF you need or desire the features Rust provides, pretty much ONLY Rust is going to get you what you want. C, C++, or Assembly potentially can deliver the same functionality, although it's questionable whether their ergonomics will be better or worse than Rusts for a given task, and they almost certainly will be more bug and error prone. Rust lets you have all the fine grained performance tweaking (or just plain low level access) you can get with C/C++/Assembly, while also giving a strong peace of mind that your code is correct and error free. It's also arguably easier than C++ although that comparison is a bit Apples and Oranges, C++ has a great many years of tweaking and experimenting behind it so things like Boost go a long way towards providing something like a most optimal (from a ergonomics standpoint) C++ experience that ignores all the languages pitfalls and sandtraps. Rust on the other hand has just barely hit 1.0 and the community hasn't even discussed, let alone come to any kind of consensus on the best way to tackle various issues yet. Rust will get there in time, but it's still early in the process and it shows.
Bottom line, if you need the features Rust provides, but aren't comfortable with how young the language is and want more hand holding, C++ (or maybe C) is probably the language you want. This isn't to say Rust is a bad language or you shouldn't use it, I think learning and using a new language is reason enough and the certainty Rusts type system and borrow checker provide is a very strong argument in its favor, but you need to be aware of what you're signing up for when you make that decision.
I can only speak for myself, and I politely disagree. So far, explicit lifetimes (both the syntax and the concepts) seem like the most uniquely Rust issue.
> [if you] want more hand holding, C++ (or maybe C) is probably the language you want.
Heh, if you think C++ holds your hand, I'm not sure we're on the same page. What I know of C++ was hard-won after reading many books and fighting with the compiler for many years.
Also, C/C++ comes with the venerable "kill the process GC" that makes it easy for beginners and other mortals to feel good about code even when it not strictly is good. Rust is all about making that kind of quality mandatory.
This is why I think the best characterization of Rust is "an Anti-Sloppy Programming Language".
I don't recall anyone ever saying this, where "the one you want" means "the one that supports procedural macros".
We have had this discussion for a very long time, and it has always centered around serde and diesel. Those have been the biggest nightly users since 1.0, and probably before then.
Not really. serde and diesel have been more convenient on nightly for a long time now. It is only just now that we can say the "next stable" because that's when the particular feature they need will be stable.
> I'll note that their story is more like "the next release will be better, but don't wait for it".
I can't wait to use Go's `sort.Slice` function[1], but I'll have to wait for the next stable release.
Seriously though, I'd say the key difference between Go and Rust on this venue is that while Rust is stable, there's still more stuff we'd like to add. To that end, we encourage experimentation by making the acquisition of a nightly Rust compiler really easy. This naturally leads to people experimenting with nightly and publishing crates that either use it or require it. This is a necessary part of experimenting with new features and getting feedback.
Go's scope for experimentation is much smaller. Their changes are much more incremental and conservative. It's a really nice benefit of using Go.
My point is: this is a trade off and it should be presented as such. In Rust land, it requires that you---the user of Rust---ignore crates that require nightly or ignore features of crates that require nightly.
I always use stable compiler. Never had a need for nightly.
Very few projects require nightly features and of those that do, most of them will work on stable in just a couple of weeks!
Plus you can easily switch between versions with rustup!
In reality, they often work perfectly fine on a reasonably-modern stable, and simply haven't updated their documentation and READMEs to indicate "oh yeah, this nightly feature is now in stable, so just use a stable that's newer than version so-and-so".
Until they don't again because clearly the authors have no interest in being on a stable compiler release.
> Plus you can easily switch between versions with rustup!
I don't think people are complaining because switching versions is hard. Just unnecessary, risky, and yes kind of annoying.
This is false, most uses of nightly are because of macros, which will be stable in the next version of Rust.
Then use an older version of the package. Unless the package in question was relying on some "nightly" feature that never made it into stable, then you should be fine.
I'm not convinced the problem will just go away. Not as long as people are obsessed with the new hotness language features that require a compiler from the tuesday before last.
Cargo also makes me wary. How do I know what I'm choosing is any good, and if it is will it still be around next year. Nature of 3rd party libs I guess.
Basically, some people like having a curated library set; others do fine without and are happy to find things to use. The former set doesn't like rust as much in its current state.
All the libraries I have needed for my projects in Rust support stable. Maybe shortly after 1.0 some people were not playing by the rules yet.
The only exceptions I've found are some truly elite macro things and stuff to support code generation.
This is compiler version pinning. At least .toml files don't support that. Yet.
The "namespace hack" in Rust is having the "stable" namespace: a compiler that rejects all unstable code (and is forward compatible), so that people don't accidentally get pinned.
If someone wants to pin to a specific development version (of anything), there's nothing the project can do about that, other than being closed source and only publishing stable artifacts. Tooling like rustup that makes it easier to pin means that people who choose to experiment can still use stable by default (easy to switch back) and that others can easily collaborate on the experiments, both of which seem like strict positives.
I went through a similar experience in Haskell. It is worth going through until you get to the point where it is no longer a wrestling match, because then you are just as productive but any code you write is checked much more thoroughly than in a more weakly typed language.
> Fuck. This. Noise. I'm not learning a language where every project requires a separate compiler.
I guess just wait until it stabilises then.
Which is when? 1.15? 1.50? 2.0?
What was the point of that whole "1.0" thing?
This is a rhetorical question, as there's no way you've been around here so long without knowing what it is. For everyone else, however, the notion is that code written for 1.0 will continue to work for additional 1.x releases. It says nothing about iterating on not-yet-baked features--that's what nightly is for, and as they become baked they become part of 1.x releases. They're not breaking backwards compatibility; the major version remains the major version.
Very few projects require the nightly compiler and fewer still a specific version of it, but rocket is highly experimental and kind of a special case.
you cannot uncomment the comments in the main function and use it wrong, the compiler prevents you to compile this code.
these two sections from the book may help understad this
https://doc.rust-lang.org/book/ownership.html
https://doc.rust-lang.org/book/references-and-borrowing.html
if you're more into videos this may help
As it stands, Rust code can break the principle of least surprise, since what happens in a method can affect the associated instance variable (in this case `open_socket`). A user could easily write several lines of code and only discover that `open_socket` has been moved into a method at compile-time.
I found myself having very small coding-compile iterations when writing in Rust to catch issues like this (but that was also undoubtedly due to the fact I was learning).
Is there a pro tip to avoid this issue?
I'm in the middle of reading the Rust book right now, so this may be dumb, but... Isn't this exactly the point of using a naked `self` instead of the reference `&self`? If it's not a reference, `self` is consumed by the method. At least that's my current understanding
If you mean that the one-character difference is very small for such an important semantic distinction, I might agree.
As for the state machine example, I like it a lot as well. It's very similar to the idea of "making illegal states unrepresentable" from the OCaml world: http://fsharpforfunandprofit.com/posts/designing-with-types-... (This particular post is F#, but the idea is general.)
Yes it is, but you only see it's a naked self if you look into the method. From the outside there's nothing in the name to indicate that it doesn't take a reference. So potentially it means that for every method call you need to check that it takes a reference to `self` instead of ownership. This would be especially annoying with third-party libraries.
In Rust, I personally don't think about moving vs. not until the compiler tells me I have to, because it usually doesn't matter. Rust previously required moves to be explicitly marked, but it wasn't worth it in practice: http://smallcultfollowing.com/babysteps/blog/2012/10/01/move... (see "Wait, doesn’t this make it hard to know what your program does?" in particular.)
Steve Klabnik has a more complete write up regarding this http://words.steveklabnik.com/structure-literals-vs-construc...
let new_socket = OpenSocket { port: 12 };TL;DR: compile time checking that your state machine transition is correct.
What sucks about programming in Rust? What makes it a bloody fucking fuck? I disagree on both these points: