I would argue that it is better than C for its safety features alone. I hope in the future we look back at this decade with its never ending stream of buffer overflow vulnerabilities with disbelief that we could use something so insecure for something so vital.
Somehow along the way UNIX spread into the enterprise and brought C along.
I've always liked to think of myself as a programming polyglot, able to pick up and reason about nearly any standard language. I'm not sure how Rust is doing it, but the more I read and learn about it, the more confused I am. The syntax is just so bizarre and counter-intuitive to me. And yet I seem to be the only person in the world who doesn't "get" it. It's as if the language is being explicitly developed to be my kryptonite.
I think in Haskell's case, it's just doing too much with too little. Like how they can implement quicksort in three short lines of code, and to me it's just so much to unroll in my head at once; but it's hard to be sure for obvious reasons.
1. Forget everything you know and follow the types.
Really? What part of the syntax in particular?
impl<'a> AnyRefExt<'a> for &'a Header {
#[inline]
fn as_ref<T: 'static>(self) -> Option<&'a T> {
trait UncheckedAnyRefExt<'a> {
unsafe fn as_ref_unchecked<T: 'static>(self) -> &'a T;
}
//I am guessing the second line is special because Rust can't deduce "to" should be a TraitObject type?
let raw = require_single_field!(raw);
let to: TraitObject = transmute_copy(&self);
//is this adding header and 'static together?
pub trait HeaderMarker<OutputType: Header + 'static> {
//I have zero clue what this is doing
//I can't even fathom a guess
match *self {
Past => write!(f.buf, "0"),
ExpiresDate(ref tm) => tm.fmt_header(f),
}
//so _raw is a reference to a vector of bytes inside [] and it might possibly return whatever a box is of headers?
fn parse_header(_raw: &[Vec<u8>]) -> Option<Box<Header>> {
//is there really a language keyword called macro_rules! ?
macro_rules! impl_header_from_fromstr {
//what in the world is ($ty:ty)?
($ty:ty) => (impl Header for $ty {
fn parse_header(raw: &[Vec<u8>]) -> Option<$ty> {
//who thought "h.is::<H>()" was a good way to test a type? Why not "h.is(H)?" Why the => ?
//what is this even returning? a tuple of false and None?
Typed(ref h) if h.is::<H>() => {
(false, None)
},
//... why not UTF-8? Because "{}"?
format_args!(format_but_not_utf8, "{}", HeaderShowAdapter(h))
The names don't make any sense to me at all. What the hell is an AnyRefExt? How does an UncheckedAnyRefExt differ? What in the world is the match thing doing? Why the asterisk on self? Why all the apostrophes and colons and dollar signs and exclamation points? Why is there both -> and =>? How does an &' differ from a '?I could probably learn the language with a huge time investment. But for something aiming to fill the role of systems programming, it's just so incredibly different from everything else. It almost feels like they are going out of their way to make it as different as possible.
I know, this is all syntax stuff. C++ template meta-programming syntax is pretty insane, too, and took me a while to pick up. Yet when I attempt to read up on the syntax and the reasoning, it becomes even more confusing. I don't expect them to write a C++ clone, I understand this is their own language. But just a tiny modicum of reflection that people have spent 15+ years learning the syntaxes and behaviors of C-like languages would be so greatly appreciated. I mean, you see how Haskell is doing, and a lot of people blame that on the absolutely alien syntax to anything programmers are used to.
Yet, with Rust, everyone else with C-family backgrounds just seem to look at this, and go, "oh yeah that makes sense." Boggles my mind.
> I am guessing the second line is special because Rust
> can't deduce "to" should be a TraitObject type?
`transmute` and its kin are stdlib functions used to completely subvert the type system by casting any one type to any other type of the same size in memory. Their use is highly discouraged since they're so easy to misuse. You're correct in that Rust cannot deduce what `to` is supposed to be on this line (because by definition `transmute` is freeform and there is no context to infer the resultant type), hence requiring an explicit type annotation. > is this adding header and 'static together?
Within trait bounds, `+` allows you to specify multiple bounds for a generic type. So it's not adding, but it's taking the union. :) > so _raw is a reference to a vector of bytes inside []
> and it might possibly return whatever a box is of
> headers?
`_raw` is a reference to an array of vectors of bytes (in this case, a reference to an array of various binary data which has already been read into byte vectors). `parse_headers` will either return a heap-allocated header (`Box` is just a bog-standard thing allocated on the heap), or, if it fails to parse for whatever reason, it will return a value that clearly indicates that an error occurred. > is there really a language keyword called macro_rules! ?
Nope, it's just a macro (that just so happens to be used to define other macros). > who thought "h.is::<H>()" was a good way to test a
> type? Why not "h.is(H)?"
Type parameters are usually inferred, so you don't want them mucking up your actual parameter list. In C++ it would look like `is<H>()`, which is much nicer, except that this requires conflating parsing with type checking (see also http://en.wikipedia.org/wiki/The_lexer_hack). Rust thinks this is gross, so it arbitrarily uses `::` to denote the beginning a type parameter list in that context. It's gross, it sucks, it's literally the worst thing about Rust's syntax and 100% of people you survey will agree with you. But fortunately you rarely need to use it because type inference works so well. But inference can't here because Chris is trying to show off Rust's `Any` type, which is a library type that can be used to emulate dynamic typing, which requires a type switch to actually use the type for anything. > what is this even returning? a tuple of false and None?
Correct! > why not UTF-8? Because "{}"?
Beats me, this line is goofy. :) `format_args!` is an implementation detail for string formatting in Rust, it's unheard of to use it directly. > What the hell is an AnyRefExt?
It's an implementation detail that was copied-and-pasted out of the stdlib specifically to facilitate this code snippet. We typically don't bother to fuss over the identifiers of things that users should never need to worry about. :) > How does an UncheckedAnyRefExt differ?
You'd have to ask Chris Morgan, Rust has no control over what users name their own types! > What in the world is the match thing doing?
It's just a beefed-up switch statement, ubiquitous throughout Rust code as it is used for working with enums (tagged unions). See http://doc.rust-lang.org/guide.html#match > Why the asterisk on self?
The asterisk is the dereference operator, the same as C. > Why all the apostrophes and colons and dollar signs and
> exclamation points?
Apostrophes: ML-inspired syntax to syntactically distinguish lifetime parameters. You see one, it means you're looking at a lifetime.Colons: you'll have to be more specific, colons are literally every programming language designer's favorite symbol.
Dollar signs: only ever used while defining macros, which you should rarely ever read and even more rarely use.
Exclamation points: used to denote that you're using a macro and that what looks like a function call is actually going to expand to arbitrary code at compile time.
> Why is there both -> and =>?
`->` is used on functions and denotes the return type of the function. That's all it's used for. `=>` is used within `match`: `foo => bar` in Rust is the same as `case foo: bar` in C. That's all it's used for. > How does an &' differ from a '?
An apostrophe just indicates a lifetime, which all references have (though they're inferred in the overwhelming majority of cases).Many of the above things would have been made clear by reading the tutorial (http://doc.rust-lang.org/guide.html). I encourage you to do so if you'd like to learn more! Feel free to also hop onto our IRC channel at irc.mozilla.org to ask any questions at all, even ones that you think are stupid or obvious. :)
> you have chosen the worst possible piece of Rust code for someone who has never looked at the language before
That's my luck :P
I was in the middle of turning my HTTP message library from a series of "setHeaderName(value)" functions into just a single "setHeader(name, value)" and was told it had some innovative ideas on how to handle HTTP headers. And I have no doubt it does ... if I could make any sense of it.
Really glad to hear a lot of the vague names were library-specific, the really evil stuff shouldn't ever be used (though I'd argue it shouldn't be exposed outside of the stdlib if true), you definitely cleared up -> and => beautifully, I think the excess colons are a type annotation (used to 'type name' and not 'name: [type]'), and although I still have some questions (around ' and & specifics), I'll read up on your guide instead. Thanks again!
Different compared to: most programming languages? Systems programming languages? Just C/++?
> I mean, you see how Haskell is doing, and a lot of people blame that on the absolutely alien syntax to anything programmers are used to.
Its syntax fits how it operates. Should Haskell have -() at the end of functions, like C-like and ML? No, since Haskell uses partial application and currying - the ()-stuff would likely end up as cruft. A function of three arguments in Haskell is not passing in three values as a tuple: it is a function that takes one argument and returns a function - that function is a function that takes one argument and returns a function... how is that clear when you write it as `f(x,y,z)? Not to mention if you partially apply it.
Can you write Haskell code as a sequence of declarations and expressions? Arguably no, since it has non-strict evaluation; having a list of declarations and expressions would be misleading, since they can really be evaluated in any order.
What can be contested is the significant layout (though it is optional) and user-definable operators. Though I think Haskell code would become really crufty without operators, since they sometimes make expressions more clear than a series of prefix-oriented functions.
> is this adding header and 'static together?
Have you written any Java code? There is basically the same thing, except they use & instead of + to build unions of type bounds.
And about all the * and & stuff: That's pointer stuff. It is very similar to how it works in C/C++. I think it's just a bit simpler in Rust (you are required to use & to pass something by reference where in C++ you don't see at the call site if something is passed by value or by reference).
About Box: Terms like "auto boxing" are known from other languages (Java), so this is not a new terminology invented by Rust.
-> for defining the return type of a function is also not an invention of Rust. I don't know many functional languages but Haskell uses it, and C++11 uses it! So coming from C++ you should know that. ;)
If the Rust compiler is stopping you from doing something, there's good chance you really shouldn't be doing it.
I think Rust does a lot of things nicely, but I don't expect it to replace C simply because it adds a lot of complexity that people don't really want to deal with.
Incorrect.
"By using theorem proving and strict type checking, the compiler can detect and prove that its implemented functions are not susceptible to bugs such as division by zero, memory leaks, buffer overflow, and other forms of memory corruption by verifying pointer arithmetic and reference counting before the program compiles."[0]
0: http://en.wikipedia.org/wiki/ATS_%28programming_language%29
Rust makes sure you are checking those things. Some of those checks are only at compile time and have no runtime cost. Others have a runtime cost but in the vast majority of situations the 'performance hit' will be negligible. Anywhere it is important you would rearrange your code to move the checking out of any critical path.
Note that it's still the same thing you'd have to be doing in C anyway to be both correct and fast. Rust just makes sure you don't forget the correct bit.
http://doc.rust-lang.org/nightly/intro.html#safety-<em>and</...
Regarding complexity and being cumbersome, Rust increases compile time dependency, but reduces debugging complexity.
Personally I would rather spend a bit more time at compile time thinking about memory ownership than spending hours (or even days/weeks) tracking down memory problems.