Rust Guide
doc.rust-lang.org
doc.rust-lang.org
I'll admit right up front that there is a lot of subjective bias here, different people learn in different ways and you will never please everyone. So I'm not saying you are wrong, just that the guide appeals to me.
In terms of the A/B split on target audience:
A - Newbs) I'd argue that teaching people to code is way, way beyond the scope of any document like this, so the most logical starting target is someone who codes already but maybe doesn't have a ton of experience and maybe it is in a language very different from the one the guide is presenting. I think this guide hits that target pretty well as a straight-forward read. There are nitpicky things that maybe could be better, but luckily online guides like this can be expanded and iterated on.
Obviously a newb isn't going to understand something like what a "closure" is inherently, but they have the whole rest of the internet to tell them that when they see the term in this guide and then google it to fill in the blanks.
B - Non-Newbs) As an experienced programmer I think the guide is actually pretty great if you use the nicely presented ToC/index at the front as the primary interface to it. Click a concept and boom, you're looking at some nicely formatted example code along with some text that you can probably just skip over completely or skim because you already know what a closure is (for example) and just want to see the syntax for Rust.
I remain a diehard Go partisan for now, but I think this guide is actually superior in a lot of ways to the combination of the "Go Tour" and "Effective Go" which, cute mascot aside, are a bit too much on the dry/clinical side for me as introductory material to a language.
I do agree that it falls into the pit you describe, but I disagree that it's the style that's doing it. I think the style is fine, although there are always people it could turn off (e.g., you, perhaps).
Here's an example of him falling into that pit, though:
> By the way, in these examples, i indicates that the number is an integer.
Ok, that's an important detail! You have to be reading _very_ closely to read that line. An expert will be skimming (as you say) and someone less less expert might not even realize how important that fact is.
If I had to list "Five Rust Facts About Integers and Variable Bindings," noting that you signal an integer literal with that "i" character would definitely be on that list! As it's written, it's emphasized no more or less than any other part of the text.
Most of that I've picked up over the last 20 years, but not all of it (or else I wouldn't be reading the books) so I constantly felt like I was having something I knew explained to me in too much detail or having crazy new concepts thrown at me without enough context.
I mostly felt sorry for total newcomers, particularly as I realised most of my knowledge was historical trivia or workarounds rather than actual useful. Once I noticed the above, the amount of crufty irrelevances we have to deal with became obvious, and that's doubly true in JS for the browser.
My only constructive thought was to break things into smaller skippable sections. I personally would skim rather than skip, but advanced warning that the section would only cover stuff I thought I already knew would be helpful.
This philosophy is stated pretty clearly in the beginning of the book:
You know how other books go on and on about programming fundamentals and finally work up to building a complete, working program? Let's skip all that.
2.1. Diving in
Here is a complete, working Python program.
It probably makes absolutely no sense to you. Don't worry about that, because you're going to dissect it line by line. But read through it first and see what, if anything, you can make of it.
See: http://www.diveintopython.net/getting_to_know_python/index.h...
I tell them stuff and leave out the things that seem obvious to me. They can tell me, what is the missing bit.
It's a new language with some interestinf semantics than can be tricky even for those familiar with say C or Java or Python etc, so it's good that it's conversational -- it helps cater to both the new programmer and the experienced one in other languages.
The skipping of cruft part I can do by myself, using "vgrep".
This "skipping of cruft" because we're talking to "experienced programmers" is what makes Manfiles nearly useless, EVEN for experienced programmers, unless as a very basic flag reference.
1- Read the manfile.
2- If I was just trying to figure out the meaning of a flag, I'm done.
3- If it was anything else, I space out trying to understand the no-nonsense, terse, written-for-programmers style of the manfile. I usually fail.
4- Google.
Many manpages, of course, do not provide examples.
I do agree with you though. I felt the same way about the guide from the first time I read (parts of) it, and I know we're not alone. I've commented before about how it's impossible to nail down the target audience, but it seems overly informal as a replacement to the current tutorials, especially compared to the "additional guides" that were linked to at the conclusion of the tutorial which really got down to business quickly.
I've long been hoping that something like rustbyexample.com gets officially sanctioned and linked to from the homepage alongside the guide. As a small metric, the current tutorial is 942 to Hello World, the new guide is 1595 words, and rustbyexample.com is 239 words.
Heck, I loved "Learn You a Haskell," yet this one reads very patronizing for some reason, and I can't figure out why.
It's usually possible to omit pronouns and end up shorter, maybe at the cost of ending up a little dryer:
"Welcome to the Rust guide. This is the place to learn how to program in Rust. Rust is a systems programming language with a focus on "high-level, bare-metal programming": low level control, but with zero-cost, higher level abstractions. We really think Rust is something special, and we hope you do too.
The guide starts with a traditional "Hello, World!" program. Next a quick detour to introduce "Cargo", a tool for managing and building Rust programs and libraries. Then it's back to the language."
If the guide actually builds something, the last sentence there could say "Then it's back to the language, starting with the basics and working up to <thing that is built>."
The Guide is fine as a tutorial and where does it not teach the basics?
So your impression is definitely not mine. "Stop talkting to me informally" is also very subjective. I very much prefer the informal way.
Is there any place to read about the Rust design?
My guess is that by far the most likely reader of this document is a noob to Rust with some degree of experience in other languages. To be safe we'll only assume basic programming experience. As a more experienced programmer, I don't mind seeing a few explanations of things I already know. From that perspective, this guide is a good compromise, once the technical issues are solved.
1. Consider this a 'first draft.' I wrote this in sections, see [1], and now it's time to edit as a whole.
2. Because of that, there are still changes coming. There's even an active one in the queue right now. [2]
3. This guide is fairly long (The PDF is 80~ pages), tries to make little assumptions about systems programming knowledge, and will get you from 'I know nothing about Rust' to 'I'm an intermediate Rust programmer.' There's plans to make an abridged version for people who are already familiar with systems or want something faster with less explanation.
To expand on (3) a bit, one of the hard parts of teaching is that you have such varying background levels of skill in your audience. This means different people need different things, one learning resource will never fit all. I very specifically went for extra explanation and an informal tone with this piece, based on my years of experience teaching programmers new languages. You all here are generally much further along, know more programming concepts and features, and are just generally more advanced. I want to include _everyone_ with the introductory documentation I write, and that means spelling things out a bit more. And it also means you all may not like it. You'll probably prefer the abridged version.
Feedback very welcome. I'll read all this eventually, or just open some issues.
1: https://github.com/rust-lang/rust/pulls?q=is%3Apr+author%3As...
Who do we have to harangue to get Rust to rename "Vector"? It is kind of embarrassing and confusing terminology, and there is no reason to propagate it. Just call an array an array and an immutable array an immutable array.
There's no good reason to perpetuate the mistakes of the C++ people.
(Note to those not understanding the objection: A vector is defined an element of a group that is closed under addition and multiplication. This is a very specific and very widely-useful meaning, and any program that does stuff with math is going to use vectors. So when you come along and put into your standard the idea that 'vector' means an arbitrary collection of elements that probably are not even scalars, you not only show that you don't know what vector means, but you confuse the programs of many many of your users, because now they have two totally different things both of which are called Vector and that are both used very heavily. [There is no way in hell anyone is going to call a math vector anything but vector, since that would be insanely confusing.])
I feel as though we can retain understanding of those differences without using the name "Vec", which can be considered a poor choice for the reasons mentioned above (by C++ and Rust alike).
Array<T> for a growable array
[T, ..N] for a fixed-length array
&[T] for a slice into either of these array types
Even forgetting the mathematical concept, I would argue that throwing the term "Vector" into the mix only makes things more complicated than they need to be, since sticking to "Array" homogenizes everything. For good reason, we don't call a resizable string a "Hobnob" in an attempt to disambiguate, so why call a resizable array a "Vector", which makes just as much sense?
I think that he manages to serve both audiences: new programmers, and experienced programmers who are new to Python. He achieves this, I think, through two main methods:
1. The emphasis is always on doing things. He introduces and explains the language concepts while using the constructs he's explaining to achieve an understandable task.
2. Code comes first, explanations come after. Hence the title, "Diving Into". Chapter 1 shows this very well: http://www.diveintopython3.net/your-first-python-program.htm..., as does the chapter on classes and iterators: http://www.diveintopython3.net/iterators.html
The idea is that the emphasis and structure enable experienced programmers to quickly recognize "Oh, that's how that is done here - I can move on", but new programmers can also see applications that accomplish some task, and then read line-by-line how it works. Code always has a context.
I was originally intending on having the guide by driven by sample projects, but I had a hard time making it work when introducing just one thing at a time. I think that's the difference here: I want to build up from small things, rather than say "here's a big thing, you may not understand it all." That approach is the one I'll be using for the abridged guide.
Negative feedback is being pruned and buried.
A ridiculous bikeshed did get downvoted a bunch though. See https://news.ycombinator.com/item?id=8310203
> "We expected an integer, but we got (). () is pronounced 'unit', and is a special type in Rust's type system. () is different than null in other languages, because () is distinct from other types"
Would it not be more accurate and more informative to compare the "special type" unit to "void" than to compare it to "null" ?
The keyword "void" is a placeholder that says "nothing here" where normally there would be a type. It function more or less like a type. i.e. "public void foo { ... };" instead of "public int foo() { ... };"
I understand "unit" as a "first class void".
"null" on the other hand is a value, that can be placed in variables of many types.
null is not a type. void type is inhabited. unit type has exactly one value, ().
That's why I said void is "more or less like a type" and asked about "unit" as a "first class void" - i.e. a "void" that is a real type that works like other types.
Not exactly first-class but useful at times.
I think null is wrong too, because it references the fact that in most languages, types are a sum type of "all possible valid inputs" plus "null". Rust avoids null and has no null pointers unless you use unsafe code.
Unit means "there is precisely one instance of this type". It is the unitary type.
While your post is correct for () the type, if I consider () the value, your post could be transformed without loss of accuracy to:
Void is not a value either, and you cannot return it from a function. I think null is a closer match.
Value or type neither half is the whole story.
For example, in the testing section, the first example code generates an error because it's scope is private. The section then shows how to fix this. I would prefer he showed the correct way first and then how to fix common errors.
Also, I didn't see file IO but i probably overlooked that.
Other than that, it's excellent. Very thorough and reads like a book.
- Most important, and nota bene: I liked it!
- this seems to be targeted as a crossover guide for experienced c/java/C++/C# family devs, but written a little below that level (whereas tutorial would be for people that have some programming experience in any language
- top level summaries before you launch into litany of language features: what is the object model, are there entities that can be inherited, how do interfaces/traits/mixins? how does allocation/initialization/destruction/cleanup typically work?
- Needs to note conventions ("_" in file/directory names, 4 space soft tabs) vs things enforced by compiler/tooling
- needs inline references/footnotes/bibliography for H-M type inference, FP style pattern matching, i.e. the "new" FP concepts for people without haskell/ocaml/scala experience
And then, perhaps, used some platform detection to display the more appropriate form by default.
That way less space is used up by the parallel examples.
There are lots of small things I would want to change about the guide, especially in regards to which sections should be more in depth and which ones should be skipped for another guide, but that's why it's a first iteration.
let x = 5i;
so, integers are written like complex numbers?`5` would be signed or unsigned if left off. Depends on how you use it.
So you could try.
use std::num::abs;
let v = vec!['a', 'b', 'c', 'd'];
let x = 3;
let c = v[x]; // v.index (operator overload) constrains x to type uint.
let y = abs(x); // error: failed to find an implementation of trait core::num::Signed for uint.
// abs can't constain the type to an int because abs can take anything that
// implements `Signed` (eg BigInt)
If you wanted to make sure that x was signed. let v = vec!['a', 'b', 'c', 'd'];
let x = 3i;
let y = abs(x); // Ok as x is signed.
let c = v[x]; // error: mismatched types: expected `uint` but found `int`
If you really wanted to index to try an index with an int you can use a checked cast. let casted = x.to_uint(); // Returns None if x is negative or Some(x) if it's postive.
Also a generic int doesn't have to be int or uint, it can be any integer value: signed: i8, i16, i32, i64 or int. Unsigned: u8, u16, u32, u64 or uint.let x: int = 5;
As far as i being an unfortunate suffix, I can't think of a better one when you consider there is already a pattern to such suffixes (being the first letter of the type) carried over from C/C++, et al.
I suspect mathematician programmers who are already used to * being multiply and ^ being bitwise xor (instead of, say, an exponent operation) can probably learn to deal with it, or just avoid it by avoiding implicit typing for ints.
(* 2+3i 4+5i) ;=> -7+22i
>>> 5 + 2j
(5+2j)
>>> 2j * 2j
(-4+0j) #include <complex.h>
complex f(complex a, complex b) {
return a*b + 5*I;
}At least get rid of the wholly-unnecessary sudo. At that point, it would at least be comparable to tar xvzf rust.tgz && ./rustc (still less auditable though).
The cool thing about Rust is that it guides you towards writing performant code, with a much lower likelihood of ugly bugs. This means it has a lower barrier to entry that languages like C++ or C, where you need a high level of domain specific knowledge and experience in to avoid nasty pitfalls and mistakes.
That said I think the language is still too much in flux to really use for production systems. It seems to still be undergoing syntax changes, standard library changes, etc that might make code that works today not compile tomorrow.
There's a group of game developers writing Piston: http://www.piston.rs/
It's a decent start, but needs some serious editing.
Good luck!
On the other hand, Rust is aimed at being a replacement for C++ or even C: it allows for precise control over lower-level aspects of the machine while providing more static guarantees of correctness by means of a powerful type system. For example, Rust prevents dangling and null pointers and disallows access to uninitialized memory while retaining manual memory management, as well as allowing garbage collection as a library-provided feature and not a core language feature. In that sense, Rust is suitable for problem domains that Go is not.
When you see Rust it's clear that they have taken note of these advances and added them to the language. Pattern Matching, Algebraic Data Types, Hindley-Milner type inference accompanied by a sophisticated type system, everything is an expression (well, most), immutable variables by default and type classes are all things that many of us who were exposed to the functional world miss sorely in mainstream languages like Java. Rust includes all of them while Golang doesn't, and C++ doesn't have some of them.
And it doesn't end there, in Rust you can also do OOP, though it's different from Java (no classes, more similar to Go). You have concurrency primitives baked into the language as in Go. You have generics as in C++ (the most cited criticism of Go, which lacks them). It lets you manage memory but in a safer way than C. And it can be made compatible with C, which lets a library written in Rust be used by other languages.
So, Rust really feels like the superior replacement of C++, and possibly C, that Golang promised at first, and it has a chance of becoming mainstream when it's stable. Rust offers all the things that Golang does, and many more. The tooling is generally better in Go, but it surely can be improved.
Lack of garbage collector ? There is a garbage collector in the standard library : http://doc.rust-lang.org/std/gc/
It gives you even more control I would say as you can choose when/if to use a garbage collector. Which is not always a bad idea (See https://news.ycombinator.com/item?id=8263811)
I've gone through and cleaned up all the references to it in our docs and marketing, so we stop misleading people with this notion.
As we wrote more and more Rust, it became clear that unique ownership (~T, now Box<T>) was just as useful, faster, and better. Remember, this type basically compiles down to a regular pointer, with compiler inserted malloc/free. So you can imagine how much less that is compared to a refcount + cycle detection.
So, Gc<T> was never really improved, and it's usage in the compiler itself was less and less. The last place it was used was in the AST, and so syntax extensions used it, but we didn't recommend it for anything else.
Now, this past week, a contributor managed to re-write the AST to not use Gc<T>, so even than is gone. Or will be soon, I forget if it's passed CI so far. But anyway, now that it's gone, it will probably be simply removed, though that decision hasn't been made yet.
Basically, what it means is that affine types are awesome.
How is anyone supposed to read fn main(). Fun main? Fen main? F of N? Is it related to ln in println?
Ive tried rust, but it just doesnt parse well in my mind. More time is spent for me parseing out the bullshit terse keywords than the meaning of the program.
Ada gets this right, there you have to write exactly what you mean, end begin, if then. Simple clear.
Terseness, shorts and abbrevations, thts now hw you wrt anyng.
I know it's trendy to remove all non alnum characters and make everything super verbose but there's a compromise to make here. Because some languages went overboard with symbol soup doesn't mean all symbols/abbreviations are bad.
This is the kind of reacting any newcomer to a language makes. You start with lisp? "omg all those parens!" You start with python? "omg significant whitespace!" You start with C? "OMG all those semicolon at the end of lines!" You start with perl? "OMG!" You start with APL? "O|▼".
Also I think making basic language constructs overly verbose doesn't help legibility because it drowns the actually interesting bits in a lot of boilerplate. VHDL comes to mind, but it's probably not what you were talking about...
as box break continue crate else enum extern false fn for if impl in let loop match mod mut priv proc pub ref return self static struct super true trait type unsafe use whilefwiw, continue and return used to be cont and ret, match used to be alt, crate used to be not a keyword iirc.
It's historical. Rust's keywords used to be far more short on average - I think the rule was no more than 5 characters.
fun would have been better: - ML heritage for named functions (fn was anon) - muscle memory with the leading part of javascript function - the other abbreviations take the leading part of the word
fn calculate() does not lead my brain/mind to discover everything there is it already knows that is function and what it means in this specific context, but instead if I read it as fun it takes me to fun times calculating tip at college with friends.
mod means modification. Modulus. Or module. Why oh why, cant they just write freaking word module?!
Thats what programming is about - kill assumptions, define stuff, and Rust is flowing with assumptions and tersness.
Ada is what I am talking about - a very fine verbose language. Even Java is better than rust.
I think if Mozilla designed Java, it would look like this
pub cls Dfne {
priv stat fin Str hey;
}
In Rust, the function keyword is written 'fn', there're no assumptions or ambiguity there. You just have to learn "in Rust fn means function". It's as capricious as any other keyword, including function.
As a non-native English speaker I find this amusing because for me it's very clear that keywords are magic incantations for the compiler or interpreter, they aren't meant to explain anything. You just learn how to use those keywords and deal with it. For me, it's not clearer to write function instead of fn because in my native language you write it 'función'.
In my experience, it's not rare for Spanish-speaking programmers to ommit the t in function as it is the clearest and most natural way for them to write it. Then, when the program doesn't work, they have to add the missing ts. I feel fn is an improvement with regards to this, as it's not so English-centered. Let's stop pretending that programming a computer is a mixture of Logic, Math and English.
The most powerful metaphor I use when I explain to newer developers how to write clear code is simply "tell a story." Of course you're telling a very constrained story, and some parts need a little comment to explain them, but I strongly believe that even if you're using english keywords, you should be telling a story in the development team's native language if possible. Not everything is a binary choice, even in computing. ;)
I humorously read it in my head as "fuckin' main".
Instead of, what, cryptic symbols to decipher?
You dont read symbols?
Also, what's the problem with pronouncing 'fn' as 'ef-en'?
Thank you.
Somewhere, a transliteration vim plugin is struggling to escape. Based on user preferences it will display:
def Σ():
print("LOL WUT?")
Σ()
-or- define sum():
print("LOL WUT?")
sum()
-or- Ξ Σ
⍋("LOL WUT?")
Σ
-or even- IDENTIFICATION DIVISION.
PROGRAM-ID. Abomination.
PROCEDURE DIVISION.
DisplaySummary.
DISPLAY "LOL WUT".
STOP RUN.I just wonder, who would have thought of such an idea. That is genious. And something that has completely evaded Rust designers.
You do. The symbol is given meaning by context.
> who would have thought of such an idea.
That would be me.
> genius
Weed, caffeine, and sleep deprivation. Staring at Harris mainframe assembly language core dumps on reams of green bar paper... does things to a man. ;-)
HTML5 and Unicode are wonderful toys. Go play. My notes and early efforts on this go back to 1979. Anyone is welcome to them. It does take quite a bit of effort to transmit, so patience is a virtue here.
(P.S. Don't overlook color.)
(P.P.S. Or animation.)
---
Edit: You'd be surprised how easy input becomes. It removes a huge mental load from context switching (e.g. hitting the same button to get Control F4, Control W, Apple W, Alt F Alt C, etc.).
Use a few touchpads which can change the symbols based on current context, and baby - you got a stew goin'.
Take care.
“If you've been playing poker for half an hour and you still don't know who the patsy is, you're the patsy.” - Warren J. "Doc" Gates
Programmers are the patsy that businesses and universities use to keep growing ever larger heads of broccoli that consumers eat.
Note the similarities between GUI's 30 years ago and today: http://en.wikipedia.org/wiki/History_of_the_graphical_user_i....
Try to wrap your head around how many API's, tools, training materials, releases, updates and so forth have been done in thirty years which are effectively redundant.
The iWatch will contain regurgitations of the same todo lists, logging, sticky notes, etc. as the Palm Pilot, but without AAA batteries.
But python at least doesnt have the goal it seems to make abbrevations and allow misconceptions about what the language is saying.
Why not use brk, cont as well? Somethings are abbreviated, some things are not.
Variable declaration and type annotations in rust are the thing you should be confused/angry/sad about.
cdr and car requires me to know 60-year-old implementation details of Lisp.
Also i'd much rather live without type inference, so I guess rust gives me that option. I'm just too neurotic (low level networking code/parsers/etc) to not specify types.
let mut monster_size: int = 50;
I'd really really just like the type to be first. let mut int monster_size = 50;
But wait, there are yet more options: let monster_size = 50i32;
Boxes are just plain confusing on first sight. They make pointers look like a lucid breath of fresh air. let owned = box 10i;
let borrowed = &20i;
let sum = *owned + *borrowed;
I find options in a language quite distressing (see also perl). I'm also not sold on the mut keyword and i'm likely to become confused when one gets to complex types.Don't get me started on the automatic dereferencing. That's seriously confusing.
Is there a rule of thumb for when I am meant to use which of these? can i use the type annotation anywhere i use a number as a literal?
Raw string literals:
> They are written as r##"blah"##, with a matching number of zero or more # before the opening and after the closing quote
Why? Why the optional number of #'s?Syntax extensions? !
Why is print a syntax extension? why isn't it in the library? if it is a macro why are we running around putting ! at the end of them... why does it matter? Why do that?
I prob don't know what I'm talking about but that's my initial impression from last week
Why? Why the optional number of #'s?
Code generation. You can nest raw literals within raw literals. Boxes are just plain confusing on first sight.
They are special way to allocate values. They are verbose so that programmers won't use them as often. Think of them as a speed bump.Boxes and lifetimes get a bit used to, but comparing Perl and Rust is, I feel, quite unfair. Rust's syntax is much smaller than Perl's, and from what I've seen the team has taken pains to make it smaller and more regular.
As for println!, it's a macro which gives you compile-time checks on your format string (same as OCaml), which is very nice.
print is a macro so it can be strongly typed and checked by the compiler. As far as I know, "!" is just a convention to make macros obvious -- it seems unnecessary to me, too.
Putting the type of a variable at the end is common in new C-likes. Go does it too. In the case of Rust, I'm pretty sure it's inherited from ML. It avoids a lot of the problems and complexities caused by C's type keywords (see: typedefs of pointers to functions; const pointers to values and pointers to const values; etc.).
No, it's very necessary, as macros actually take arbitrary token sequences as an 'argument', so there's no guarantee that the contents will parse as Rust code (e.g. https://github.com/huonw/brainfuck_macros), furthermore, macros can transform this argument into arbitrary code.
Hence it's nice to have an in-source marker to avoid humans and compilers having to work out if a certain name has strange semantics (particularly for compilers, to avoid having to intertwine parsing and name resolution: makes this simpler).
It is important for syntax highlighters.
fn foo<<W<>W>G<>GGW>>>F<<D>F>>A>(bar: AJK<<<DUoSJK><<>S>>>){
...
}
Okay, I'm probably being a jackass, but I find Scala's use of [] for nested type annotations to be much easier to parse. from_str::<Option<uint>>
vs from_str::‹Opton‹uint››
Hmm. Those are a little lightweight, are actually angle quotes, not angle brackets. Actual angle brackets aren't available on my keyboard, but would look like: from_str::⟨Option⟨uint⟩⟩
Jeez, why does Unicode have so many different variations on angle brackets? The above are "mathematical left/right angle bracket", but there's also: from_str::〈Option〈uint〉〉
Which uses "left/right-pointing angle bracket" and: from_str::〈Option〈uint〉〉
Which uses "left/right angle bracket"At least in the font I'm typing this in, the "left/right-pointing angle brackets" look the best to me. It would be really nice if now that Unicode is ubiquitous, we could standardize on keyboard layouts that get you access to more punctuation like this, so that people didn't have to keep fighting over a fairly limited amount of punctuation to use as technical notation in programming languages.
const foo = {bar: @a, baz : asd(@a,foo(@b, bar(@c,@d),int))
...
}